Browse Source

Merge pull request #2031 from dymanoid/sdk-style-csproj

SDK style C# project files
pull/2044/head
Siegfried Pammer 5 years ago committed by GitHub
parent
commit
a2e45f3cdd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 5
      ICSharpCode.Decompiler.Console/IlspyCmdProgram.cs
  2. 5
      ICSharpCode.Decompiler.PowerShell/GetDecompiledProjectCmdlet.cs
  3. 2
      ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj
  4. 121
      ICSharpCode.Decompiler.Tests/ProjectDecompiler/TargetFrameworkTests.cs
  5. 42
      ICSharpCode.Decompiler.Tests/RoundtripAssembly.cs
  6. 28
      ICSharpCode.Decompiler.Tests/TestAssemblyResolver.cs
  7. 41
      ICSharpCode.Decompiler/CSharp/ProjectDecompiler/IProjectFileWriter.cs
  8. 49
      ICSharpCode.Decompiler/CSharp/ProjectDecompiler/IProjectInfoProvider.cs
  9. 175
      ICSharpCode.Decompiler/CSharp/ProjectDecompiler/ProjectFileWriterDefault.cs
  10. 212
      ICSharpCode.Decompiler/CSharp/ProjectDecompiler/ProjectFileWriterSdkStyle.cs
  11. 142
      ICSharpCode.Decompiler/CSharp/ProjectDecompiler/TargetFramework.cs
  12. 129
      ICSharpCode.Decompiler/CSharp/ProjectDecompiler/TargetServices.cs
  13. 314
      ICSharpCode.Decompiler/CSharp/ProjectDecompiler/WholeProjectDecompiler.cs
  14. 1
      ICSharpCode.Decompiler/DebugInfo/PortablePdbWriter.cs
  15. 18
      ICSharpCode.Decompiler/DecompilerSettings.cs
  16. 8
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  17. 1
      ICSharpCode.Decompiler/Metadata/AssemblyReferences.cs
  18. 5
      ICSharpCode.Decompiler/Metadata/UniversalAssemblyResolver.cs
  19. 9
      ILSpy/Languages/CSharpLanguage.cs
  20. 5
      ILSpy/LoadedAssembly.cs
  21. 9
      ILSpy/Properties/Resources.Designer.cs
  22. 3
      ILSpy/Properties/Resources.resx
  23. 3
      ILSpy/Properties/Resources.zh-Hans.resx
  24. 2
      ILSpy/TextView/DecompilerTextView.cs

5
ICSharpCode.Decompiler.Console/IlspyCmdProgram.cs

@ -13,6 +13,7 @@ using System.Reflection.Metadata; @@ -13,6 +13,7 @@ using System.Reflection.Metadata;
using System.Reflection.PortableExecutable;
using ICSharpCode.Decompiler.DebugInfo;
using ICSharpCode.Decompiler.PdbProvider;
using ICSharpCode.Decompiler.CSharp.ProjectDecompiler;
// ReSharper disable All
namespace ICSharpCode.Decompiler.Console
@ -175,14 +176,12 @@ Remarks: @@ -175,14 +176,12 @@ Remarks:
int DecompileAsProject(string assemblyFileName, string outputDirectory)
{
var decompiler = new WholeProjectDecompiler() { Settings = GetSettings() };
var module = new PEFile(assemblyFileName);
var resolver = new UniversalAssemblyResolver(assemblyFileName, false, module.Reader.DetectTargetFrameworkId());
foreach (var path in ReferencePaths) {
resolver.AddSearchDirectory(path);
}
decompiler.AssemblyResolver = resolver;
decompiler.DebugInfoProvider = TryLoadPDB(module);
var decompiler = new WholeProjectDecompiler(GetSettings(), resolver, TryLoadPDB(module));
decompiler.DecompileProject(module, outputDirectory);
return 0;
}

5
ICSharpCode.Decompiler.PowerShell/GetDecompiledProjectCmdlet.cs

@ -5,6 +5,7 @@ using System.Management.Automation; @@ -5,6 +5,7 @@ using System.Management.Automation;
using System.Threading;
using System.Threading.Tasks;
using ICSharpCode.Decompiler.CSharp;
using ICSharpCode.Decompiler.CSharp.ProjectDecompiler;
using ICSharpCode.Decompiler.Metadata;
namespace ICSharpCode.Decompiler.PowerShell
@ -77,9 +78,9 @@ namespace ICSharpCode.Decompiler.PowerShell @@ -77,9 +78,9 @@ namespace ICSharpCode.Decompiler.PowerShell
private void DoDecompile(string path)
{
WholeProjectDecompiler decompiler = new WholeProjectDecompiler();
PEFile module = Decompiler.TypeSystem.MainModule.PEFile;
decompiler.AssemblyResolver = new UniversalAssemblyResolver(module.FileName, false, module.Reader.DetectTargetFrameworkId());
var assemblyResolver = new UniversalAssemblyResolver(module.FileName, false, module.Reader.DetectTargetFrameworkId());
WholeProjectDecompiler decompiler = new WholeProjectDecompiler(assemblyResolver);
decompiler.ProgressIndicator = this;
fileName = module.FileName;
completed = 0;

2
ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj

@ -88,6 +88,8 @@ @@ -88,6 +88,8 @@
<Compile Include="..\ILSpy\DebugInfo\DebugInfoUtils.cs" Link="DebugInfoUtils.cs" />
<Compile Include="..\ILSpy\DebugInfo\PortableDebugInfoProvider.cs" Link="PortableDebugInfoProvider.cs" />
<Compile Include="DisassemblerPrettyTestRunner.cs" />
<Compile Include="ProjectDecompiler\TargetFrameworkTests.cs" />
<Compile Include="TestAssemblyResolver.cs" />
<Compile Include="TestCases\Correctness\StringConcat.cs" />
<Compile Include="TestCases\ILPretty\Issue1681.cs" />
<None Include="TestCases\Pretty\IndexRangeTest.cs" />

121
ICSharpCode.Decompiler.Tests/ProjectDecompiler/TargetFrameworkTests.cs

@ -0,0 +1,121 @@ @@ -0,0 +1,121 @@
// Copyright (c) 2020 Daniel Grunwald
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using ICSharpCode.Decompiler.CSharp.ProjectDecompiler;
using NUnit.Framework;
namespace ICSharpCode.Decompiler.Tests
{
[TestFixture]
public sealed class TargetFrameworkTests
{
[TestCase(-1)]
[TestCase(0)]
[TestCase(1)]
[TestCase(99)]
[TestCase(int.MinValue)]
public void VerifyThrowsForInvalidVersion(int invalidVersion)
{
// Arrange - nothing
// Act
void CreateInstance() => new TargetFramework(identifier: null, invalidVersion, profile: null);
// Assert
Assert.Throws<ArgumentException>(CreateInstance);
}
[TestCase(100, "v1.0")]
[TestCase(102, "v1.0.2")]
[TestCase(130, "v1.3")]
[TestCase(145, "v1.4.5")]
[TestCase(1670, "v16.7")]
[TestCase(1800, "v18.0")]
public void VerifyVersion(int version, string expectedVersion)
{
// Arrange - nothing
// Act
var targetFramework = new TargetFramework(identifier: null, version, profile: null);
// Assert
Assert.AreEqual(version, targetFramework.VersionNumber);
Assert.AreEqual(expectedVersion, targetFramework.VersionString);
}
[Test]
public void VerifyPortableLibrary()
{
// Arrange
const string identifier = ".NETPortable";
// Act
var targetFramework = new TargetFramework(identifier, 100, profile: null);
// Assert
Assert.IsTrue(targetFramework.IsPortableClassLibrary);
Assert.AreEqual(identifier, targetFramework.Identifier);
}
[Test]
[Pairwise]
public void VerifyIdentifierAndProfile(
[Values(null, "", ".NETFramework")] string identifier,
[Values(null, "", ".Client")] string profile)
{
// Arrange - nothing
// Act
var targetFramework = new TargetFramework(identifier, 100, profile);
// Assert
Assert.AreEqual(identifier, targetFramework.Identifier);
Assert.AreEqual(profile, targetFramework.Profile);
}
[TestCase(null, 350, "net35")]
[TestCase(".NETFramework", 350, "net35")]
[TestCase(".NETFramework", 400, "net40")]
[TestCase(".NETFramework", 451, "net451")]
[TestCase(".NETCoreApp", 200, "netcoreapp2.0")]
[TestCase(".NETCoreApp", 310, "netcoreapp3.1")]
[TestCase(".NETStandard", 130, "netstandard1.3")]
[TestCase(".NETStandard", 200, "netstandard2.0")]
[TestCase("Silverlight", 400, "sl4")]
[TestCase("Silverlight", 550, "sl5")]
[TestCase(".NETCore", 450, "netcore45")]
[TestCase(".NETCore", 451, "netcore451")]
[TestCase("WindowsPhone", 700, "wp7")]
[TestCase("WindowsPhone", 810, "wp81")]
[TestCase(".NETMicroFramework", 100, "netmf")]
[TestCase(".NETMicroFramework", 210, "netmf")]
[TestCase(".NETPortable", 100, null)]
[TestCase("Unsupported", 100, null)]
public void VerifyMoniker(string identifier, int version, string expectedMoniker)
{
// Arrange - nothing
// Act
var targetFramework = new TargetFramework(identifier, version, profile: null);
// Assert
Assert.AreEqual(expectedMoniker, targetFramework.Moniker);
}
}
}

42
ICSharpCode.Decompiler.Tests/RoundtripAssembly.cs

@ -24,6 +24,7 @@ using System.Reflection.PortableExecutable; @@ -24,6 +24,7 @@ using System.Reflection.PortableExecutable;
using System.Text.RegularExpressions;
using System.Threading;
using ICSharpCode.Decompiler.CSharp;
using ICSharpCode.Decompiler.CSharp.ProjectDecompiler;
using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.Tests.Helpers;
using Microsoft.Build.Locator;
@ -54,7 +55,7 @@ namespace ICSharpCode.Decompiler.Tests @@ -54,7 +55,7 @@ namespace ICSharpCode.Decompiler.Tests
public void NewtonsoftJson_pcl_debug()
{
try {
RunWithTest("Newtonsoft.Json-pcl-debug", "Newtonsoft.Json.dll", "Newtonsoft.Json.Tests.dll");
RunWithTest("Newtonsoft.Json-pcl-debug", "Newtonsoft.Json.dll", "Newtonsoft.Json.Tests.dll", useOldProjectFormat: true);
} catch (CompilationFailedException) {
Assert.Ignore("Cannot yet re-compile PCL projects.");
}
@ -102,9 +103,9 @@ namespace ICSharpCode.Decompiler.Tests @@ -102,9 +103,9 @@ namespace ICSharpCode.Decompiler.Tests
RunWithOutput("Random Tests\\TestCases", "TestCase-1.exe");
}
void RunWithTest(string dir, string fileToRoundtrip, string fileToTest, string keyFile = null)
void RunWithTest(string dir, string fileToRoundtrip, string fileToTest, string keyFile = null, bool useOldProjectFormat = false)
{
RunInternal(dir, fileToRoundtrip, outputDir => RunTest(outputDir, fileToTest), keyFile);
RunInternal(dir, fileToRoundtrip, outputDir => RunTest(outputDir, fileToTest), keyFile, useOldProjectFormat);
}
void RunWithOutput(string dir, string fileToRoundtrip)
@ -119,7 +120,7 @@ namespace ICSharpCode.Decompiler.Tests @@ -119,7 +120,7 @@ namespace ICSharpCode.Decompiler.Tests
RunInternal(dir, fileToRoundtrip, outputDir => { });
}
void RunInternal(string dir, string fileToRoundtrip, Action<string> testAction, string snkFilePath = null)
void RunInternal(string dir, string fileToRoundtrip, Action<string> testAction, string snkFilePath = null, bool useOldProjectFormat = false)
{
if (!Directory.Exists(TestDir)) {
Assert.Ignore($"Assembly-roundtrip test ignored: test directory '{TestDir}' needs to be checked out separately." + Environment.NewLine +
@ -147,16 +148,22 @@ namespace ICSharpCode.Decompiler.Tests @@ -147,16 +148,22 @@ namespace ICSharpCode.Decompiler.Tests
Stopwatch w = Stopwatch.StartNew();
using (var fileStream = new FileStream(file, FileMode.Open, FileAccess.Read)) {
PEFile module = new PEFile(file, fileStream, PEStreamOptions.PrefetchEntireImage);
var resolver = new UniversalAssemblyResolver(file, false, module.Reader.DetectTargetFrameworkId(), PEStreamOptions.PrefetchMetadata);
var resolver = new TestAssemblyResolver(file, inputDir, module.Reader.DetectTargetFrameworkId());
resolver.AddSearchDirectory(inputDir);
resolver.RemoveSearchDirectory(".");
var decompiler = new TestProjectDecompiler(inputDir);
decompiler.AssemblyResolver = resolver;
// use a fixed GUID so that we can diff the output between different ILSpy runs without spurious changes
var projectGuid = Guid.Parse("{127C83E4-4587-4CF9-ADCA-799875F3DFE6}");
// Let's limit the roundtrip tests to C# 7.3 for now; because 8.0 is still in preview
// and the generated project doesn't build as-is.
decompiler.Settings = new DecompilerSettings(LanguageVersion.CSharp7_3);
// use a fixed GUID so that we can diff the output between different ILSpy runs without spurious changes
decompiler.ProjectGuid = Guid.Parse("{127C83E4-4587-4CF9-ADCA-799875F3DFE6}");
var settings = new DecompilerSettings(LanguageVersion.CSharp7_3);
if (useOldProjectFormat) {
settings.UseSdkStyleProjectFormat = false;
}
var decompiler = new TestProjectDecompiler(projectGuid, resolver, settings);
if (snkFilePath != null) {
decompiler.StrongNameKeyFile = Path.Combine(inputDir, snkFilePath);
}
@ -208,7 +215,7 @@ namespace ICSharpCode.Decompiler.Tests @@ -208,7 +215,7 @@ namespace ICSharpCode.Decompiler.Tests
static void Compile(string projectFile, string outputDir)
{
var info = new ProcessStartInfo(FindMSBuild());
info.Arguments = $"/nologo /v:minimal /p:OutputPath=\"{outputDir}\" \"{projectFile}\"";
info.Arguments = $"/nologo /v:minimal /restore /p:OutputPath=\"{outputDir}\" \"{projectFile}\"";
info.CreateNoWindow = true;
info.UseShellExecute = false;
info.RedirectStandardOutput = true;
@ -259,18 +266,9 @@ namespace ICSharpCode.Decompiler.Tests @@ -259,18 +266,9 @@ namespace ICSharpCode.Decompiler.Tests
class TestProjectDecompiler : WholeProjectDecompiler
{
readonly string[] localAssemblies;
public TestProjectDecompiler(string baseDir)
{
localAssemblies = new DirectoryInfo(baseDir).EnumerateFiles("*.dll").Select(f => f.FullName).ToArray();
}
protected override bool IsGacAssembly(IAssemblyReference r, PEFile asm)
public TestProjectDecompiler(Guid projecGuid, IAssemblyResolver resolver, DecompilerSettings settings)
: base(settings, projecGuid, resolver, debugInfoProvider: null)
{
if (asm == null)
return false;
return !localAssemblies.Contains(asm.FileName);
}
}

28
ICSharpCode.Decompiler.Tests/TestAssemblyResolver.cs

@ -0,0 +1,28 @@ @@ -0,0 +1,28 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection.Metadata;
using System.Reflection.PortableExecutable;
using ICSharpCode.Decompiler.Metadata;
namespace ICSharpCode.Decompiler.Tests
{
sealed class TestAssemblyResolver : UniversalAssemblyResolver
{
readonly HashSet<string> localAssemblies = new HashSet<string>();
public TestAssemblyResolver(string mainAssemblyFileName, string baseDir, string targetFramework)
: base(mainAssemblyFileName, false, targetFramework, PEStreamOptions.PrefetchMetadata, MetadataReaderOptions.ApplyWindowsRuntimeProjections)
{
var assemblyNames = new DirectoryInfo(baseDir).EnumerateFiles("*.dll").Select(f => Path.GetFileNameWithoutExtension(f.Name));
foreach (var name in assemblyNames) {
localAssemblies.Add(name);
}
}
public override bool IsGacAssembly(IAssemblyReference reference)
{
return reference != null && !localAssemblies.Contains(reference.Name);
}
}
}

41
ICSharpCode.Decompiler/CSharp/ProjectDecompiler/IProjectFileWriter.cs

@ -0,0 +1,41 @@ @@ -0,0 +1,41 @@
// Copyright (c) 2020 Siegfried Pammer
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System.Collections.Generic;
using System.IO;
using ICSharpCode.Decompiler.Metadata;
namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler
{
/// <summary>
/// An interface for a service that creates and writes a project file structure
/// for a specific module being decompiled.
/// </summary>
interface IProjectFileWriter
{
/// <summary>
/// Writes the content of a new project file for the specified <paramref name="module"/> being decompiled.
/// </summary>
/// <param name="target">The target to write to.</param>
/// <param name="project">The information about the project being created.</param>
/// <param name="files">A collection of source files to be included into the project, each item is a pair
/// of the project entry type and the file path.</param>
/// <param name="module">The module being decompiled.</param>
void Write(TextWriter target, IProjectInfoProvider project, IEnumerable<(string itemType, string fileName)> files, PEFile module);
}
}

49
ICSharpCode.Decompiler/CSharp/ProjectDecompiler/IProjectInfoProvider.cs

@ -0,0 +1,49 @@ @@ -0,0 +1,49 @@
// Copyright (c) 2020 Daniel Grunwald
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using ICSharpCode.Decompiler.Metadata;
namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler
{
/// <summary>
/// An interface that provides common information for a project being decompiled to.
/// </summary>
interface IProjectInfoProvider
{
/// <summary>
/// Gets the assembly resolver active for the project.
/// </summary>
IAssemblyResolver AssemblyResolver { get; }
/// <summary>
/// Gets the C# language version of the project.
/// </summary>
LanguageVersion LanguageVersion { get; }
/// <summary>
/// Gets the unique ID of the project.
/// </summary>
Guid ProjectGuid { get; }
/// <summary>
/// Gets the name of the key file being used for strong name signing. Can be null if no file is available.
/// </summary>
string StrongNameKeyFile { get; }
}
}

175
ICSharpCode.Decompiler/CSharp/ProjectDecompiler/ProjectFileWriterDefault.cs

@ -0,0 +1,175 @@ @@ -0,0 +1,175 @@
// Copyright (c) 2020 Siegfried Pammer
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection.PortableExecutable;
using System.Xml;
using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.Solution;
namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler
{
/// <summary>
/// A <see cref="IProjectFileWriter"/> implementation that creates the projects in the default format.
/// </summary>
sealed class ProjectFileWriterDefault : IProjectFileWriter
{
/// <summary>
/// Creates a new instance of the <see cref="ProjectFileWriterDefault"/> class.
/// </summary>
/// <returns>A new instance of the <see cref="ProjectFileWriterDefault"/> class.</returns>
public static IProjectFileWriter Create() => new ProjectFileWriterDefault();
/// <inheritdoc />
public void Write(
TextWriter target,
IProjectInfoProvider project,
IEnumerable<(string itemType, string fileName)> files,
PEFile module)
{
const string ns = "http://schemas.microsoft.com/developer/msbuild/2003";
string platformName = TargetServices.GetPlatformName(module);
var targetFramework = TargetServices.DetectTargetFramework(module);
List<Guid> typeGuids = new List<Guid>();
if (targetFramework.IsPortableClassLibrary)
typeGuids.Add(ProjectTypeGuids.PortableLibrary);
typeGuids.Add(ProjectTypeGuids.CSharpWindows);
using (XmlTextWriter w = new XmlTextWriter(target)) {
w.Formatting = Formatting.Indented;
w.WriteStartDocument();
w.WriteStartElement("Project", ns);
w.WriteAttributeString("ToolsVersion", "4.0");
w.WriteAttributeString("DefaultTargets", "Build");
w.WriteStartElement("PropertyGroup");
w.WriteElementString("ProjectGuid", project.ProjectGuid.ToString("B").ToUpperInvariant());
w.WriteElementString("ProjectTypeGuids", string.Join(";", typeGuids.Select(g => g.ToString("B").ToUpperInvariant())));
w.WriteStartElement("Configuration");
w.WriteAttributeString("Condition", " '$(Configuration)' == '' ");
w.WriteValue("Debug");
w.WriteEndElement(); // </Configuration>
w.WriteStartElement("Platform");
w.WriteAttributeString("Condition", " '$(Platform)' == '' ");
w.WriteValue(platformName);
w.WriteEndElement(); // </Platform>
if (module.Reader.PEHeaders.IsDll) {
w.WriteElementString("OutputType", "Library");
} else {
switch (module.Reader.PEHeaders.PEHeader.Subsystem) {
case Subsystem.WindowsGui:
w.WriteElementString("OutputType", "WinExe");
break;
case Subsystem.WindowsCui:
w.WriteElementString("OutputType", "Exe");
break;
default:
w.WriteElementString("OutputType", "Library");
break;
}
}
w.WriteElementString("LangVersion", project.LanguageVersion.ToString().Replace("CSharp", "").Replace('_', '.'));
w.WriteElementString("AssemblyName", module.Name);
if (targetFramework.Identifier != null)
w.WriteElementString("TargetFrameworkIdentifier", targetFramework.Identifier);
if (targetFramework.VersionString != null)
w.WriteElementString("TargetFrameworkVersion", targetFramework.VersionString);
if (targetFramework.Profile != null)
w.WriteElementString("TargetFrameworkProfile", targetFramework.Profile);
w.WriteElementString("WarningLevel", "4");
w.WriteElementString("AllowUnsafeBlocks", "True");
if (project.StrongNameKeyFile != null) {
w.WriteElementString("SignAssembly", "True");
w.WriteElementString("AssemblyOriginatorKeyFile", Path.GetFileName(project.StrongNameKeyFile));
}
w.WriteEndElement(); // </PropertyGroup>
w.WriteStartElement("PropertyGroup"); // platform-specific
w.WriteAttributeString("Condition", " '$(Platform)' == '" + platformName + "' ");
w.WriteElementString("PlatformTarget", platformName);
if (targetFramework.VersionNumber > 400 && platformName == "AnyCPU" && (module.Reader.PEHeaders.CorHeader.Flags & CorFlags.Prefers32Bit) == 0) {
w.WriteElementString("Prefer32Bit", "false");
}
w.WriteEndElement(); // </PropertyGroup> (platform-specific)
w.WriteStartElement("PropertyGroup"); // Debug
w.WriteAttributeString("Condition", " '$(Configuration)' == 'Debug' ");
w.WriteElementString("OutputPath", "bin\\Debug\\");
w.WriteElementString("DebugSymbols", "true");
w.WriteElementString("DebugType", "full");
w.WriteElementString("Optimize", "false");
w.WriteEndElement(); // </PropertyGroup> (Debug)
w.WriteStartElement("PropertyGroup"); // Release
w.WriteAttributeString("Condition", " '$(Configuration)' == 'Release' ");
w.WriteElementString("OutputPath", "bin\\Release\\");
w.WriteElementString("DebugSymbols", "true");
w.WriteElementString("DebugType", "pdbonly");
w.WriteElementString("Optimize", "true");
w.WriteEndElement(); // </PropertyGroup> (Release)
w.WriteStartElement("ItemGroup"); // References
foreach (var r in module.AssemblyReferences) {
if (r.Name != "mscorlib") {
w.WriteStartElement("Reference");
w.WriteAttributeString("Include", r.Name);
var asm = project.AssemblyResolver.Resolve(r);
if (asm != null && !project.AssemblyResolver.IsGacAssembly(r)) {
w.WriteElementString("HintPath", asm.FileName);
}
w.WriteEndElement();
}
}
w.WriteEndElement(); // </ItemGroup> (References)
foreach (IGrouping<string, string> gr in from f in files group f.fileName by f.itemType into g orderby g.Key select g) {
w.WriteStartElement("ItemGroup");
foreach (string file in gr.OrderBy(f => f, StringComparer.OrdinalIgnoreCase)) {
w.WriteStartElement(gr.Key);
w.WriteAttributeString("Include", file);
w.WriteEndElement();
}
w.WriteEndElement();
}
if (targetFramework.IsPortableClassLibrary) {
w.WriteStartElement("Import");
w.WriteAttributeString("Project", "$(MSBuildExtensionsPath32)\\Microsoft\\Portable\\$(TargetFrameworkVersion)\\Microsoft.Portable.CSharp.targets");
w.WriteEndElement();
} else {
w.WriteStartElement("Import");
w.WriteAttributeString("Project", "$(MSBuildToolsPath)\\Microsoft.CSharp.targets");
w.WriteEndElement();
}
w.WriteEndDocument();
}
}
}
}

212
ICSharpCode.Decompiler/CSharp/ProjectDecompiler/ProjectFileWriterSdkStyle.cs

@ -0,0 +1,212 @@ @@ -0,0 +1,212 @@
// Copyright (c) 2020 Siegfried Pammer
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection.PortableExecutable;
using System.Xml;
using ICSharpCode.Decompiler.Metadata;
namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler
{
/// <summary>
/// A <see cref="IProjectFileWriter"/> implementation that creates the projects in the SDK style format.
/// </summary>
sealed class ProjectFileWriterSdkStyle : IProjectFileWriter
{
const string AspNetCorePrefix = "Microsoft.AspNetCore";
const string PresentationFrameworkName = "PresentationFramework";
const string WindowsFormsName = "System.Windows.Forms";
const string TrueString = "True";
const string FalseString = "False";
const string AnyCpuString = "AnyCPU";
static readonly HashSet<string> ImplicitReferences = new HashSet<string> {
"mscorlib",
"netstandard",
"PresentationFramework",
"System",
"System.Diagnostics.Debug",
"System.Diagnostics.Tools",
"System.Drawing",
"System.Runtime",
"System.Runtime.Extensions",
"System.Windows.Forms",
"System.Xaml",
};
enum ProjectType { Default, WinForms, Wpf, Web }
/// <summary>
/// Creates a new instance of the <see cref="ProjectFileWriterSdkStyle"/> class.
/// </summary>
/// <returns>A new instance of the <see cref="ProjectFileWriterSdkStyle"/> class.</returns>
public static IProjectFileWriter Create() => new ProjectFileWriterSdkStyle();
/// <inheritdoc />
public void Write(
TextWriter target,
IProjectInfoProvider project,
IEnumerable<(string itemType, string fileName)> files,
PEFile module)
{
using (XmlTextWriter xmlWriter = new XmlTextWriter(target)) {
xmlWriter.Formatting = Formatting.Indented;
Write(xmlWriter, project, module);
}
}
static void Write(XmlTextWriter xml, IProjectInfoProvider project, PEFile module)
{
xml.WriteStartElement("Project");
var projectType = GetProjectType(module);
xml.WriteAttributeString("Sdk", GetSdkString(projectType));
PlaceIntoTag("PropertyGroup", xml, () => WriteAssemblyInfo(xml, module, projectType));
PlaceIntoTag("PropertyGroup", xml, () => WriteProjectInfo(xml, project));
PlaceIntoTag("ItemGroup", xml, () => WriteReferences(xml, module, project));
xml.WriteEndElement();
}
static void PlaceIntoTag(string tagName, XmlTextWriter xml, Action content)
{
xml.WriteStartElement(tagName);
try {
content();
} finally {
xml.WriteEndElement();
}
}
static void WriteAssemblyInfo(XmlTextWriter xml, PEFile module, ProjectType projectType)
{
xml.WriteElementString("AssemblyName", module.Name);
// Since we create AssemblyInfo.cs manually, we need to disable the auto-generation
xml.WriteElementString("GenerateAssemblyInfo", FalseString);
// 'Library' is default, so only need to specify output type for executables
if (!module.Reader.PEHeaders.IsDll) {
WriteOutputType(xml, module.Reader.PEHeaders.PEHeader.Subsystem);
}
WriteDesktopExtensions(xml, projectType);
string platformName = TargetServices.GetPlatformName(module);
var targetFramework = TargetServices.DetectTargetFramework(module);
if (targetFramework.Moniker == null) {
throw new NotSupportedException($"Cannot decompile this assembly to a SDK style project. Use default project format instead.");
}
xml.WriteElementString("TargetFramework", targetFramework.Moniker);
// 'AnyCPU' is default, so only need to specify platform if it differs
if (platformName != AnyCpuString) {
xml.WriteElementString("PlatformTarget", platformName);
}
if (platformName == AnyCpuString && (module.Reader.PEHeaders.CorHeader.Flags & CorFlags.Prefers32Bit) != 0) {
xml.WriteElementString("Prefer32Bit", TrueString);
}
}
static void WriteOutputType(XmlTextWriter xml, Subsystem moduleSubsystem)
{
switch (moduleSubsystem) {
case Subsystem.WindowsGui:
xml.WriteElementString("OutputType", "WinExe");
break;
case Subsystem.WindowsCui:
xml.WriteElementString("OutputType", "Exe");
break;
}
}
static void WriteDesktopExtensions(XmlTextWriter xml, ProjectType projectType)
{
if (projectType == ProjectType.Wpf) {
xml.WriteElementString("UseWPF", TrueString);
} else if (projectType == ProjectType.WinForms) {
xml.WriteElementString("UseWindowsForms", TrueString);
}
}
static void WriteProjectInfo(XmlTextWriter xml, IProjectInfoProvider project)
{
xml.WriteElementString("LangVersion", project.LanguageVersion.ToString().Replace("CSharp", "").Replace('_', '.'));
xml.WriteElementString("AllowUnsafeBlocks", TrueString);
if (project.StrongNameKeyFile != null) {
xml.WriteElementString("SignAssembly", TrueString);
xml.WriteElementString("AssemblyOriginatorKeyFile", Path.GetFileName(project.StrongNameKeyFile));
}
}
static void WriteReferences(XmlTextWriter xml, PEFile module, IProjectInfoProvider project)
{
foreach (var reference in module.AssemblyReferences.Where(r => !ImplicitReferences.Contains(r.Name))) {
xml.WriteStartElement("Reference");
xml.WriteAttributeString("Include", reference.Name);
var asembly = project.AssemblyResolver.Resolve(reference);
if (asembly != null) {
xml.WriteElementString("HintPath", asembly.FileName);
}
xml.WriteEndElement();
}
}
static string GetSdkString(ProjectType projectType)
{
switch (projectType) {
case ProjectType.WinForms:
case ProjectType.Wpf:
return "Microsoft.NET.Sdk.WindowsDesktop";
case ProjectType.Web:
return "Microsoft.NET.Sdk.Web";
default:
return "Microsoft.NET.Sdk";
}
}
static ProjectType GetProjectType(PEFile module)
{
foreach (var referenceName in module.AssemblyReferences.Select(r => r.Name)) {
if (referenceName.StartsWith(AspNetCorePrefix, StringComparison.Ordinal)) {
return ProjectType.Web;
}
if (referenceName == PresentationFrameworkName) {
return ProjectType.Wpf;
}
if (referenceName == WindowsFormsName) {
return ProjectType.WinForms;
}
}
return ProjectType.Default;
}
}
}

142
ICSharpCode.Decompiler/CSharp/ProjectDecompiler/TargetFramework.cs

@ -0,0 +1,142 @@ @@ -0,0 +1,142 @@
// Copyright (c) 2020 Siegfried Pammer
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Text;
namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler
{
/// <summary>
/// A class describing the target framework of a module.
/// </summary>
sealed class TargetFramework
{
const string DotNetPortableIdentifier = ".NETPortable";
/// <summary>
/// Initializes a new instance of the <see cref="TargetFramework"/> class.
/// </summary>
/// <param name="identifier">The framework identifier string. Can be null.</param>
/// <param name="version">The framework version string. Must be greater than 100 (where 100 corresponds to v1.0).</param>
/// <param name="profile">The framework profile. Can be null.</param>
public TargetFramework(string identifier, int version, string profile)
{
if (version < 100) {
throw new ArgumentException("The version number must be greater than or equal to 100", nameof(version));
}
Identifier = identifier;
VersionNumber = version;
VersionString = "v" + GetVersionString(version, withDots: true);
Moniker = GetTargetFrameworkMoniker(Identifier, version);
Profile = profile;
IsPortableClassLibrary = identifier == DotNetPortableIdentifier;
}
/// <summary>
/// Gets the target framework identifier. Can be null if not defined.
/// </summary>
public string Identifier { get; }
/// <summary>
/// Gets the target framework moniker. Can be null if not supported.
/// </summary>
public string Moniker { get; }
/// <summary>
/// Gets the target framework version, e.g. "v4.5".
/// </summary>
public string VersionString { get; }
/// <summary>
/// Gets the target framework version as integer (multiplied by 100), e.g. 450.
/// </summary>
public int VersionNumber { get; }
/// <summary>
/// Gets the target framework profile. Can be null if not set or not available.
/// </summary>
public string Profile { get; }
/// <summary>
/// Gets a value indicating whether the target is a portable class library (PCL).
/// </summary>
public bool IsPortableClassLibrary { get; }
static string GetTargetFrameworkMoniker(string frameworkIdentifier, int version)
{
// Reference: https://docs.microsoft.com/en-us/dotnet/standard/frameworks
switch (frameworkIdentifier) {
case null:
case ".NETFramework":
return "net" + GetVersionString(version, withDots: false);
case ".NETCoreApp":
return "netcoreapp" + GetVersionString(version, withDots: true);
case ".NETStandard":
return "netstandard" + GetVersionString(version, withDots: true);
case "Silverlight":
return "sl" + version / 100;
case ".NETCore":
return "netcore" + GetVersionString(version, withDots: false);
case "WindowsPhone":
return "wp" + GetVersionString(version, withDots: false, omitMinorWhenZero: true);
case ".NETMicroFramework":
return "netmf";
default:
return null;
}
}
static string GetVersionString(int version, bool withDots, bool omitMinorWhenZero = false)
{
int major = version / 100;
int minor = version % 100 / 10;
int patch = version % 10;
if (omitMinorWhenZero && minor == 0 && patch == 0) {
return major.ToString();
}
var versionBuilder = new StringBuilder(8);
versionBuilder.Append(major);
if (withDots) {
versionBuilder.Append('.');
}
versionBuilder.Append(minor);
if (patch != 0) {
if (withDots) {
versionBuilder.Append('.');
}
versionBuilder.Append(patch);
}
return versionBuilder.ToString();
}
}
}

129
ICSharpCode.Decompiler/CSharp/ProjectDecompiler/TargetServices.cs

@ -0,0 +1,129 @@ @@ -0,0 +1,129 @@
// Copyright (c) 2020 Siegfried Pammer
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Linq;
using System.Reflection.PortableExecutable;
using ICSharpCode.Decompiler.Metadata;
namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler
{
/// <summary>
/// Helper services for determining the target framework and platform of a module.
/// </summary>
static class TargetServices
{
const string VersionToken = "Version=";
const string ProfileToken = "Profile=";
/// <summary>
/// Gets the <see cref="TargetFramework"/> for the specified <paramref name="module"/>.
/// </summary>
/// <param name="module">The module to get the target framework description for. Cannot be null.</param>
/// <returns>A new instance of the <see cref="TargetFramework"/> class that describes the specified <paramref name="module"/>.
/// </returns>
public static TargetFramework DetectTargetFramework(PEFile module)
{
if (module is null) {
throw new ArgumentNullException(nameof(module));
}
int versionNumber;
switch (module.GetRuntime()) {
case TargetRuntime.Net_1_0:
versionNumber = 100;
break;
case TargetRuntime.Net_1_1:
versionNumber = 110;
break;
case TargetRuntime.Net_2_0:
versionNumber = 200;
// TODO: Detect when .NET 3.0/3.5 is required
break;
default:
versionNumber = 400;
break;
}
string targetFrameworkIdentifier = null;
string targetFrameworkProfile = null;
string targetFramework = module.DetectTargetFrameworkId();
if (!string.IsNullOrEmpty(targetFramework)) {
string[] frameworkParts = targetFramework.Split(',');
targetFrameworkIdentifier = frameworkParts.FirstOrDefault(a => !a.StartsWith(VersionToken, StringComparison.OrdinalIgnoreCase) && !a.StartsWith(ProfileToken, StringComparison.OrdinalIgnoreCase));
string frameworkVersion = frameworkParts.FirstOrDefault(a => a.StartsWith(VersionToken, StringComparison.OrdinalIgnoreCase));
if (frameworkVersion != null) {
versionNumber = int.Parse(frameworkVersion.Substring(VersionToken.Length + 1).Replace(".", ""));
if (versionNumber < 100) versionNumber *= 10;
}
string frameworkProfile = frameworkParts.FirstOrDefault(a => a.StartsWith(ProfileToken, StringComparison.OrdinalIgnoreCase));
if (frameworkProfile != null)
targetFrameworkProfile = frameworkProfile.Substring(ProfileToken.Length);
}
return new TargetFramework(targetFrameworkIdentifier, versionNumber, targetFrameworkProfile);
}
/// <summary>
/// Gets the string representation (name) of the target platform of the specified <paramref name="module"/>.
/// </summary>
/// <param name="module">The module to get the target framework description for. Cannot be null.</param>
/// <returns>The platform name, e.g. "AnyCPU" or "x86".</returns>
public static string GetPlatformName(PEFile module)
{
if (module is null) {
throw new ArgumentNullException(nameof(module));
}
var headers = module.Reader.PEHeaders;
var architecture = headers.CoffHeader.Machine;
var characteristics = headers.CoffHeader.Characteristics;
var corflags = headers.CorHeader.Flags;
switch (architecture) {
case Machine.I386:
if ((corflags & CorFlags.Prefers32Bit) != 0)
return "AnyCPU";
if ((corflags & CorFlags.Requires32Bit) != 0)
return "x86";
// According to ECMA-335, II.25.3.3.1 CorFlags.Requires32Bit and Characteristics.Bit32Machine must be in sync
// for assemblies containing managed code. However, this is not true for C++/CLI assemblies.
if ((corflags & CorFlags.ILOnly) == 0 && (characteristics & Characteristics.Bit32Machine) != 0)
return "x86";
return "AnyCPU";
case Machine.Amd64:
return "x64";
case Machine.IA64:
return "Itanium";
default:
return architecture.ToString();
}
}
}
}

314
ICSharpCode.Decompiler/CSharp/WholeProjectDecompiler.cs → ICSharpCode.Decompiler/CSharp/ProjectDecompiler/WholeProjectDecompiler.cs

@ -21,7 +21,6 @@ using System.Collections.Generic; @@ -21,7 +21,6 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Xml;
using ICSharpCode.Decompiler.CSharp.OutputVisitor;
using ICSharpCode.Decompiler.CSharp.Syntax;
using ICSharpCode.Decompiler.CSharp.Transforms;
@ -29,34 +28,24 @@ using ICSharpCode.Decompiler.TypeSystem; @@ -29,34 +28,24 @@ using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.Util;
using System.Threading;
using System.Text;
using System.Reflection.PortableExecutable;
using System.Reflection.Metadata;
using static ICSharpCode.Decompiler.Metadata.DotNetCorePathFinderExtensions;
using static ICSharpCode.Decompiler.Metadata.MetadataExtensions;
using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.Solution;
using ICSharpCode.Decompiler.DebugInfo;
namespace ICSharpCode.Decompiler.CSharp
namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler
{
/// <summary>
/// Decompiles an assembly into a visual studio project file.
/// </summary>
public class WholeProjectDecompiler
public class WholeProjectDecompiler : IProjectInfoProvider
{
#region Settings
DecompilerSettings settings = new DecompilerSettings();
public DecompilerSettings Settings {
get {
return settings;
}
set {
if (value == null)
throw new ArgumentNullException();
settings = value;
}
}
/// <summary>
/// Gets the setting this instance uses for decompiling.
/// </summary>
public DecompilerSettings Settings { get; }
LanguageVersion? languageVersion;
@ -71,15 +60,14 @@ namespace ICSharpCode.Decompiler.CSharp @@ -71,15 +60,14 @@ namespace ICSharpCode.Decompiler.CSharp
}
}
public IAssemblyResolver AssemblyResolver { get; set; }
public IAssemblyResolver AssemblyResolver { get; }
public IDebugInfoProvider DebugInfoProvider { get; set; }
public IDebugInfoProvider DebugInfoProvider { get; }
/// <summary>
/// The MSBuild ProjectGuid to use for the new project.
/// <c>null</c> to automatically generate a new GUID.
/// </summary>
public Guid? ProjectGuid { get; set; }
public Guid ProjectGuid { get; }
/// <summary>
/// Path to the snk file to use for signing.
@ -92,6 +80,32 @@ namespace ICSharpCode.Decompiler.CSharp @@ -92,6 +80,32 @@ namespace ICSharpCode.Decompiler.CSharp
public IProgress<DecompilationProgress> ProgressIndicator { get; set; }
#endregion
public WholeProjectDecompiler(IAssemblyResolver assemblyResolver)
: this(new DecompilerSettings(), assemblyResolver, debugInfoProvider: null)
{
}
public WholeProjectDecompiler(
DecompilerSettings settings,
IAssemblyResolver assemblyResolver,
IDebugInfoProvider debugInfoProvider)
: this(settings, Guid.NewGuid(), assemblyResolver, debugInfoProvider)
{
}
protected WholeProjectDecompiler(
DecompilerSettings settings,
Guid projectGuid,
IAssemblyResolver assemblyResolver,
IDebugInfoProvider debugInfoProvider)
{
Settings = settings ?? throw new ArgumentNullException(nameof(settings));
ProjectGuid = projectGuid;
AssemblyResolver = assemblyResolver ?? throw new ArgumentNullException(nameof(assemblyResolver));
DebugInfoProvider = debugInfoProvider;
projectWriter = Settings.UseSdkStyleProjectFormat ? ProjectFileWriterSdkStyle.Create() : ProjectFileWriterDefault.Create();
}
// per-run members
HashSet<string> directories = new HashSet<string>(Platform.FileNameComparer);
@ -104,6 +118,8 @@ namespace ICSharpCode.Decompiler.CSharp @@ -104,6 +118,8 @@ namespace ICSharpCode.Decompiler.CSharp
/// </remarks>
protected string targetDirectory;
readonly IProjectFileWriter projectWriter;
public void DecompileProject(PEFile moduleDefinition, string targetDirectory, CancellationToken cancellationToken = default(CancellationToken))
{
string projectFileName = Path.Combine(targetDirectory, CleanUpFileName(moduleDefinition.Name) + ".csproj");
@ -124,207 +140,19 @@ namespace ICSharpCode.Decompiler.CSharp @@ -124,207 +140,19 @@ namespace ICSharpCode.Decompiler.CSharp
if (StrongNameKeyFile != null) {
File.Copy(StrongNameKeyFile, Path.Combine(targetDirectory, Path.GetFileName(StrongNameKeyFile)));
}
return WriteProjectFile(projectFileWriter, files, moduleDefinition);
}
#region WriteProjectFile
ProjectId WriteProjectFile(TextWriter writer, IEnumerable<Tuple<string, string>> files, Metadata.PEFile module)
{
const string ns = "http://schemas.microsoft.com/developer/msbuild/2003";
string platformName = GetPlatformName(module);
Guid guid = this.ProjectGuid ?? Guid.NewGuid();
var targetFramework = DetectTargetFramework(module);
List<Guid> typeGuids = new List<Guid>();
if (targetFramework.IsPortableClassLibrary)
typeGuids.Add(ProjectTypeGuids.PortableLibrary);
typeGuids.Add(ProjectTypeGuids.CSharpWindows);
// TODO: .NET core support
using (XmlTextWriter w = new XmlTextWriter(writer)) {
w.Formatting = Formatting.Indented;
w.WriteStartDocument();
w.WriteStartElement("Project", ns);
w.WriteAttributeString("ToolsVersion", "4.0");
w.WriteAttributeString("DefaultTargets", "Build");
w.WriteStartElement("PropertyGroup");
w.WriteElementString("ProjectGuid", guid.ToString("B").ToUpperInvariant());
w.WriteElementString("ProjectTypeGuids", string.Join(";", typeGuids.Select(g => g.ToString("B").ToUpperInvariant())));
w.WriteStartElement("Configuration");
w.WriteAttributeString("Condition", " '$(Configuration)' == '' ");
w.WriteValue("Debug");
w.WriteEndElement(); // </Configuration>
w.WriteStartElement("Platform");
w.WriteAttributeString("Condition", " '$(Platform)' == '' ");
w.WriteValue(platformName);
w.WriteEndElement(); // </Platform>
if (module.Reader.PEHeaders.IsDll) {
w.WriteElementString("OutputType", "Library");
} else {
switch (module.Reader.PEHeaders.PEHeader.Subsystem) {
case Subsystem.WindowsGui:
w.WriteElementString("OutputType", "WinExe");
break;
case Subsystem.WindowsCui:
w.WriteElementString("OutputType", "Exe");
break;
default:
w.WriteElementString("OutputType", "Library");
break;
}
}
w.WriteElementString("LangVersion", LanguageVersion.ToString().Replace("CSharp", "").Replace('_', '.'));
w.WriteElementString("AssemblyName", module.Name);
if (targetFramework.TargetFrameworkIdentifier != null)
w.WriteElementString("TargetFrameworkIdentifier", targetFramework.TargetFrameworkIdentifier);
if (targetFramework.TargetFrameworkVersion != null)
w.WriteElementString("TargetFrameworkVersion", targetFramework.TargetFrameworkVersion);
if (targetFramework.TargetFrameworkProfile != null)
w.WriteElementString("TargetFrameworkProfile", targetFramework.TargetFrameworkProfile);
w.WriteElementString("WarningLevel", "4");
w.WriteElementString("AllowUnsafeBlocks", "True");
if (StrongNameKeyFile != null) {
w.WriteElementString("SignAssembly", "True");
w.WriteElementString("AssemblyOriginatorKeyFile", Path.GetFileName(StrongNameKeyFile));
}
w.WriteEndElement(); // </PropertyGroup>
w.WriteStartElement("PropertyGroup"); // platform-specific
w.WriteAttributeString("Condition", " '$(Platform)' == '" + platformName + "' ");
w.WriteElementString("PlatformTarget", platformName);
if (targetFramework.VersionNumber > 400 && platformName == "AnyCPU" && (module.Reader.PEHeaders.CorHeader.Flags & CorFlags.Prefers32Bit) == 0) {
w.WriteElementString("Prefer32Bit", "false");
}
w.WriteEndElement(); // </PropertyGroup> (platform-specific)
w.WriteStartElement("PropertyGroup"); // Debug
w.WriteAttributeString("Condition", " '$(Configuration)' == 'Debug' ");
w.WriteElementString("OutputPath", "bin\\Debug\\");
w.WriteElementString("DebugSymbols", "true");
w.WriteElementString("DebugType", "full");
w.WriteElementString("Optimize", "false");
w.WriteEndElement(); // </PropertyGroup> (Debug)
w.WriteStartElement("PropertyGroup"); // Release
w.WriteAttributeString("Condition", " '$(Configuration)' == 'Release' ");
w.WriteElementString("OutputPath", "bin\\Release\\");
w.WriteElementString("DebugSymbols", "true");
w.WriteElementString("DebugType", "pdbonly");
w.WriteElementString("Optimize", "true");
w.WriteEndElement(); // </PropertyGroup> (Release)
w.WriteStartElement("ItemGroup"); // References
foreach (var r in module.AssemblyReferences) {
if (r.Name != "mscorlib") {
w.WriteStartElement("Reference");
w.WriteAttributeString("Include", r.Name);
var asm = AssemblyResolver.Resolve(r);
if (!IsGacAssembly(r, asm)) {
if (asm != null) {
w.WriteElementString("HintPath", asm.FileName);
}
}
w.WriteEndElement();
}
}
w.WriteEndElement(); // </ItemGroup> (References)
foreach (IGrouping<string, string> gr in (from f in files group f.Item2 by f.Item1 into g orderby g.Key select g)) {
w.WriteStartElement("ItemGroup");
foreach (string file in gr.OrderBy(f => f, StringComparer.OrdinalIgnoreCase)) {
w.WriteStartElement(gr.Key);
w.WriteAttributeString("Include", file);
w.WriteEndElement();
}
w.WriteEndElement();
}
if (targetFramework.IsPortableClassLibrary) {
w.WriteStartElement("Import");
w.WriteAttributeString("Project", "$(MSBuildExtensionsPath32)\\Microsoft\\Portable\\$(TargetFrameworkVersion)\\Microsoft.Portable.CSharp.targets");
w.WriteEndElement();
} else {
w.WriteStartElement("Import");
w.WriteAttributeString("Project", "$(MSBuildToolsPath)\\Microsoft.CSharp.targets");
w.WriteEndElement();
}
w.WriteEndDocument();
}
return new ProjectId(platformName, guid, ProjectTypeGuids.CSharpWindows);
}
struct TargetFramework
{
public string TargetFrameworkIdentifier;
public string TargetFrameworkVersion;
public string TargetFrameworkProfile;
public int VersionNumber;
public bool IsPortableClassLibrary => TargetFrameworkIdentifier == ".NETPortable";
projectWriter.Write(projectFileWriter, this, files, moduleDefinition);
string platformName = TargetServices.GetPlatformName(moduleDefinition);
return new ProjectId(platformName, ProjectGuid, ProjectTypeGuids.CSharpWindows);
}
private TargetFramework DetectTargetFramework(PEFile module)
{
TargetFramework result = default;
switch (module.GetRuntime()) {
case Metadata.TargetRuntime.Net_1_0:
result.VersionNumber = 100;
result.TargetFrameworkVersion = "v1.0";
break;
case Metadata.TargetRuntime.Net_1_1:
result.VersionNumber = 110;
result.TargetFrameworkVersion = "v1.1";
break;
case Metadata.TargetRuntime.Net_2_0:
result.VersionNumber = 200;
result.TargetFrameworkVersion = "v2.0";
// TODO: Detect when .NET 3.0/3.5 is required
break;
default:
result.VersionNumber = 400;
result.TargetFrameworkVersion = "v4.0";
break;
}
string targetFramework = module.DetectTargetFrameworkId();
if (!string.IsNullOrEmpty(targetFramework)) {
string[] frameworkParts = targetFramework.Split(',');
result.TargetFrameworkIdentifier = frameworkParts.FirstOrDefault(a => !a.StartsWith("Version=", StringComparison.OrdinalIgnoreCase) && !a.StartsWith("Profile=", StringComparison.OrdinalIgnoreCase));
string frameworkVersion = frameworkParts.FirstOrDefault(a => a.StartsWith("Version=", StringComparison.OrdinalIgnoreCase));
if (frameworkVersion != null) {
result.TargetFrameworkVersion = frameworkVersion.Substring("Version=".Length);
result.VersionNumber = int.Parse(frameworkVersion.Substring("Version=v".Length).Replace(".", ""));
if (result.VersionNumber < 100) result.VersionNumber *= 10;
}
string frameworkProfile = frameworkParts.FirstOrDefault(a => a.StartsWith("Profile=", StringComparison.OrdinalIgnoreCase));
if (frameworkProfile != null)
result.TargetFrameworkProfile = frameworkProfile.Substring("Profile=".Length);
}
return result;
}
protected virtual bool IsGacAssembly(Metadata.IAssemblyReference r, Metadata.PEFile asm)
{
return false;
}
#endregion
#region WriteCodeFilesInProject
protected virtual bool IncludeTypeWhenDecompilingProject(Metadata.PEFile module, TypeDefinitionHandle type)
protected virtual bool IncludeTypeWhenDecompilingProject(PEFile module, TypeDefinitionHandle type)
{
var metadata = module.Metadata;
var typeDef = metadata.GetTypeDefinition(type);
if (metadata.GetString(typeDef.Name) == "<Module>" || CSharpDecompiler.MemberIsHidden(module, type, settings))
if (metadata.GetString(typeDef.Name) == "<Module>" || CSharpDecompiler.MemberIsHidden(module, type, Settings))
return false;
if (metadata.GetString(typeDef.Namespace) == "XamlGeneratedNamespace" && metadata.GetString(typeDef.Name) == "GeneratedInternalTypeHelper")
return false;
@ -333,14 +161,14 @@ namespace ICSharpCode.Decompiler.CSharp @@ -333,14 +161,14 @@ namespace ICSharpCode.Decompiler.CSharp
CSharpDecompiler CreateDecompiler(DecompilerTypeSystem ts)
{
var decompiler = new CSharpDecompiler(ts, settings);
var decompiler = new CSharpDecompiler(ts, Settings);
decompiler.DebugInfoProvider = DebugInfoProvider;
decompiler.AstTransforms.Add(new EscapeInvalidIdentifiers());
decompiler.AstTransforms.Add(new RemoveCLSCompliantAttribute());
return decompiler;
}
IEnumerable<Tuple<string, string>> WriteAssemblyInfo(DecompilerTypeSystem ts, CancellationToken cancellationToken)
IEnumerable<(string itemType, string fileName)> WriteAssemblyInfo(DecompilerTypeSystem ts, CancellationToken cancellationToken)
{
var decompiler = CreateDecompiler(ts);
decompiler.CancellationToken = cancellationToken;
@ -352,12 +180,12 @@ namespace ICSharpCode.Decompiler.CSharp @@ -352,12 +180,12 @@ namespace ICSharpCode.Decompiler.CSharp
Directory.CreateDirectory(Path.Combine(targetDirectory, prop));
string assemblyInfo = Path.Combine(prop, "AssemblyInfo.cs");
using (StreamWriter w = new StreamWriter(Path.Combine(targetDirectory, assemblyInfo))) {
syntaxTree.AcceptVisitor(new CSharpOutputVisitor(w, settings.CSharpFormattingOptions));
syntaxTree.AcceptVisitor(new CSharpOutputVisitor(w, Settings.CSharpFormattingOptions));
}
return new Tuple<string, string>[] { Tuple.Create("Compile", assemblyInfo) };
return new[] { ("Compile", assemblyInfo) };
}
IEnumerable<Tuple<string, string>> WriteCodeFilesInProject(Metadata.PEFile module, CancellationToken cancellationToken)
IEnumerable<(string itemType, string fileName)> WriteCodeFilesInProject(Metadata.PEFile module, CancellationToken cancellationToken)
{
var metadata = module.Metadata;
var files = module.Metadata.GetTopLevelTypeDefinitions().Where(td => IncludeTypeWhenDecompilingProject(module, td)).GroupBy(
@ -374,8 +202,8 @@ namespace ICSharpCode.Decompiler.CSharp @@ -374,8 +202,8 @@ namespace ICSharpCode.Decompiler.CSharp
}
}, StringComparer.OrdinalIgnoreCase).ToList();
int total = files.Count;
var progress = this.ProgressIndicator;
DecompilerTypeSystem ts = new DecompilerTypeSystem(module, AssemblyResolver, settings);
var progress = ProgressIndicator;
DecompilerTypeSystem ts = new DecompilerTypeSystem(module, AssemblyResolver, Settings);
Parallel.ForEach(
files,
new ParallelOptions {
@ -388,19 +216,19 @@ namespace ICSharpCode.Decompiler.CSharp @@ -388,19 +216,19 @@ namespace ICSharpCode.Decompiler.CSharp
CSharpDecompiler decompiler = CreateDecompiler(ts);
decompiler.CancellationToken = cancellationToken;
var syntaxTree = decompiler.DecompileTypes(file.ToArray());
syntaxTree.AcceptVisitor(new CSharpOutputVisitor(w, settings.CSharpFormattingOptions));
syntaxTree.AcceptVisitor(new CSharpOutputVisitor(w, Settings.CSharpFormattingOptions));
} catch (Exception innerException) when (!(innerException is OperationCanceledException || innerException is DecompilerException)) {
throw new DecompilerException(module, $"Error decompiling for '{file.Key}'", innerException);
}
}
progress?.Report(new DecompilationProgress(total, file.Key));
});
return files.Select(f => Tuple.Create("Compile", f.Key)).Concat(WriteAssemblyInfo(ts, cancellationToken));
return files.Select(f => ("Compile", f.Key)).Concat(WriteAssemblyInfo(ts, cancellationToken));
}
#endregion
#region WriteResourceFilesInProject
protected virtual IEnumerable<Tuple<string, string>> WriteResourceFilesInProject(Metadata.PEFile module)
protected virtual IEnumerable<(string itemType, string fileName)> WriteResourceFilesInProject(Metadata.PEFile module)
{
foreach (var r in module.Resources.Where(r => r.ResourceType == Metadata.ResourceType.Embedded)) {
Stream stream = r.TryOpenStream();
@ -408,7 +236,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -408,7 +236,7 @@ namespace ICSharpCode.Decompiler.CSharp
if (r.Name.EndsWith(".resources", StringComparison.OrdinalIgnoreCase)) {
bool decodedIntoIndividualFiles;
var individualResources = new List<Tuple<string, string>>();
var individualResources = new List<(string itemType, string fileName)>();
try {
var resourcesFile = new ResourcesFile(stream);
if (resourcesFile.AllEntriesAreStreams()) {
@ -449,12 +277,12 @@ namespace ICSharpCode.Decompiler.CSharp @@ -449,12 +277,12 @@ namespace ICSharpCode.Decompiler.CSharp
stream.Position = 0;
stream.CopyTo(fs);
}
yield return Tuple.Create("EmbeddedResource", fileName);
yield return ("EmbeddedResource", fileName);
}
}
}
protected virtual IEnumerable<Tuple<string, string>> WriteResourceToFile(string fileName, string resourceName, Stream entryStream)
protected virtual IEnumerable<(string itemType, string fileName)> WriteResourceToFile(string fileName, string resourceName, Stream entryStream)
{
if (fileName.EndsWith(".resources", StringComparison.OrdinalIgnoreCase)) {
string resx = Path.ChangeExtension(fileName, ".resx");
@ -465,7 +293,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -465,7 +293,7 @@ namespace ICSharpCode.Decompiler.CSharp
writer.AddResource(entry.Key, entry.Value);
}
}
return new[] { Tuple.Create("EmbeddedResource", resx) };
return new[] { ("EmbeddedResource", resx) };
} catch (BadImageFormatException) {
// if the .resources can't be decoded, just save them as-is
} catch (EndOfStreamException) {
@ -475,7 +303,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -475,7 +303,7 @@ namespace ICSharpCode.Decompiler.CSharp
using (FileStream fs = new FileStream(Path.Combine(targetDirectory, fileName), FileMode.Create, FileAccess.Write)) {
entryStream.CopyTo(fs);
}
return new[] { Tuple.Create("EmbeddedResource", fileName) };
return new[] { ("EmbeddedResource", fileName) };
}
string GetFileNameForResource(string fullName)
@ -559,32 +387,6 @@ namespace ICSharpCode.Decompiler.CSharp @@ -559,32 +387,6 @@ namespace ICSharpCode.Decompiler.CSharp
return false;
}
}
public static string GetPlatformName(Metadata.PEFile module)
{
var headers = module.Reader.PEHeaders;
var architecture = headers.CoffHeader.Machine;
var characteristics = headers.CoffHeader.Characteristics;
var corflags = headers.CorHeader.Flags;
switch (architecture) {
case Machine.I386:
if ((corflags & CorFlags.Prefers32Bit) != 0)
return "AnyCPU";
if ((corflags & CorFlags.Requires32Bit) != 0)
return "x86";
// According to ECMA-335, II.25.3.3.1 CorFlags.Requires32Bit and Characteristics.Bit32Machine must be in sync
// for assemblies containing managed code. However, this is not true for C++/CLI assemblies.
if ((corflags & CorFlags.ILOnly) == 0 && (characteristics & Characteristics.Bit32Machine) != 0)
return "x86";
return "AnyCPU";
case Machine.Amd64:
return "x64";
case Machine.IA64:
return "Itanium";
default:
return architecture.ToString();
}
}
}
public readonly struct DecompilationProgress

1
ICSharpCode.Decompiler/DebugInfo/PortablePdbWriter.cs

@ -30,6 +30,7 @@ using System.Security.Cryptography; @@ -30,6 +30,7 @@ using System.Security.Cryptography;
using System.Text;
using ICSharpCode.Decompiler.CSharp;
using ICSharpCode.Decompiler.CSharp.OutputVisitor;
using ICSharpCode.Decompiler.CSharp.ProjectDecompiler;
using ICSharpCode.Decompiler.CSharp.Syntax;
using ICSharpCode.Decompiler.IL;
using ICSharpCode.Decompiler.Metadata;

18
ICSharpCode.Decompiler/DecompilerSettings.cs

@ -1329,6 +1329,24 @@ namespace ICSharpCode.Decompiler @@ -1329,6 +1329,24 @@ namespace ICSharpCode.Decompiler
}
}
bool useSdkStyleProjectFormat = true;
/// <summary>
/// Gets or sets a value indicating whether the new SDK style format
/// shall be used for the generated project files.
/// </summary>
[Category("DecompilerSettings.Other")]
[Description("DecompilerSettings.UseSdkStyleProjectFormat")]
public bool UseSdkStyleProjectFormat {
get { return useSdkStyleProjectFormat; }
set {
if (useSdkStyleProjectFormat != value) {
useSdkStyleProjectFormat = value;
OnPropertyChanged();
}
}
}
CSharpFormattingOptions csharpFormattingOptions;
[Browsable(false)]

8
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -61,9 +61,15 @@ @@ -61,9 +61,15 @@
<Compile Include="CSharp\Annotations.cs" />
<Compile Include="CSharp\CallBuilder.cs" />
<Compile Include="CSharp\CSharpLanguageVersion.cs" />
<Compile Include="CSharp\ProjectDecompiler\IProjectFileWriter.cs" />
<Compile Include="CSharp\OutputVisitor\GenericGrammarAmbiguityVisitor.cs" />
<Compile Include="CSharp\ProjectDecompiler\IProjectInfoProvider.cs" />
<Compile Include="CSharp\ProjectDecompiler\ProjectFileWriterSdkStyle.cs" />
<Compile Include="CSharp\ProjectDecompiler\ProjectFileWriterDefault.cs" />
<Compile Include="CSharp\RequiredNamespaceCollector.cs" />
<Compile Include="CSharp\SequencePointBuilder.cs" />
<Compile Include="CSharp\ProjectDecompiler\TargetFramework.cs" />
<Compile Include="CSharp\ProjectDecompiler\TargetServices.cs" />
<Compile Include="IL\Transforms\IndexRangeTransform.cs" />
<Compile Include="CSharp\TranslatedStatement.cs" />
<Compile Include="DebugInfo\KnownGuids.cs" />
@ -277,7 +283,7 @@ @@ -277,7 +283,7 @@
<Compile Include="CSharp\Transforms\IAstTransform.cs" />
<Compile Include="CSharp\Transforms\IntroduceUnsafeModifier.cs" />
<Compile Include="CSharp\Transforms\ReplaceMethodCallsWithOperators.cs" />
<Compile Include="CSharp\WholeProjectDecompiler.cs" />
<Compile Include="CSharp\ProjectDecompiler\WholeProjectDecompiler.cs" />
<Compile Include="CSharp\Transforms\AddXmlDocumentationTransform.cs" />
<Compile Include="DecompileRun.cs" />
<Compile Include="Disassembler\ILParser.cs" />

1
ICSharpCode.Decompiler/Metadata/AssemblyReferences.cs

@ -46,6 +46,7 @@ namespace ICSharpCode.Decompiler.Metadata @@ -46,6 +46,7 @@ namespace ICSharpCode.Decompiler.Metadata
{
PEFile Resolve(IAssemblyReference reference);
PEFile ResolveModule(PEFile mainModule, string moduleName);
bool IsGacAssembly(IAssemblyReference reference);
}
public interface IAssemblyReference

5
ICSharpCode.Decompiler/Metadata/UniversalAssemblyResolver.cs

@ -173,6 +173,11 @@ namespace ICSharpCode.Decompiler.Metadata @@ -173,6 +173,11 @@ namespace ICSharpCode.Decompiler.Metadata
return new PEFile(moduleFileName, new FileStream(moduleFileName, FileMode.Open, FileAccess.Read), streamOptions, metadataOptions);
}
public virtual bool IsGacAssembly(IAssemblyReference reference)
{
return GetAssemblyInGac(reference) != null;
}
public string FindAssemblyFile(IAssemblyReference name)
{
if (name.IsWindowsRuntime) {

9
ILSpy/Languages/CSharpLanguage.cs

@ -32,6 +32,7 @@ using ICSharpCode.AvalonEdit.Utils; @@ -32,6 +32,7 @@ using ICSharpCode.AvalonEdit.Utils;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.CSharp;
using ICSharpCode.Decompiler.CSharp.OutputVisitor;
using ICSharpCode.Decompiler.CSharp.ProjectDecompiler;
using ICSharpCode.Decompiler.CSharp.Syntax;
using ICSharpCode.Decompiler.CSharp.Transforms;
using ICSharpCode.Decompiler.Metadata;
@ -437,21 +438,19 @@ namespace ICSharpCode.ILSpy @@ -437,21 +438,19 @@ namespace ICSharpCode.ILSpy
readonly DecompilationOptions options;
public ILSpyWholeProjectDecompiler(LoadedAssembly assembly, DecompilationOptions options)
: base(options.DecompilerSettings, assembly.GetAssemblyResolver(), assembly.GetDebugInfoOrNull())
{
this.assembly = assembly;
this.options = options;
base.Settings = options.DecompilerSettings;
base.AssemblyResolver = assembly.GetAssemblyResolver();
base.DebugInfoProvider = assembly.GetDebugInfoOrNull();
}
protected override IEnumerable<Tuple<string, string>> WriteResourceToFile(string fileName, string resourceName, Stream entryStream)
protected override IEnumerable<(string itemType, string fileName)> WriteResourceToFile(string fileName, string resourceName, Stream entryStream)
{
foreach (var handler in App.ExportProvider.GetExportedValues<IResourceFileHandler>()) {
if (handler.CanHandle(fileName, options)) {
entryStream.Position = 0;
fileName = handler.WriteResourceToFile(assembly, fileName, entryStream, options);
return new[] { Tuple.Create(handler.EntryType, fileName) };
return new[] { (handler.EntryType, fileName) };
}
}
return base.WriteResourceToFile(fileName, resourceName, entryStream);

5
ILSpy/LoadedAssembly.cs

@ -253,6 +253,11 @@ namespace ICSharpCode.ILSpy @@ -253,6 +253,11 @@ namespace ICSharpCode.ILSpy
this.parent = parent;
}
public bool IsGacAssembly(IAssemblyReference reference)
{
return parent.universalResolver?.IsGacAssembly(reference) == true;
}
public PEFile Resolve(Decompiler.Metadata.IAssemblyReference reference)
{
return parent.LookupReferencedAssembly(reference)?.GetPEFileOrNull();

9
ILSpy/Properties/Resources.Designer.cs generated

@ -1109,6 +1109,15 @@ namespace ICSharpCode.ILSpy.Properties { @@ -1109,6 +1109,15 @@ namespace ICSharpCode.ILSpy.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to Use new SDK style format for generated project files (*.csproj).
/// </summary>
public static string DecompilerSettings_UseSdkStyleProjectFormat {
get {
return ResourceManager.GetString("DecompilerSettings.UseSdkStyleProjectFormat", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Use stackalloc initializer syntax.
/// </summary>

3
ILSpy/Properties/Resources.resx

@ -870,4 +870,7 @@ Do you want to continue?</value> @@ -870,4 +870,7 @@ Do you want to continue?</value>
<data name="NewTab" xml:space="preserve">
<value>New Tab</value>
</data>
<data name="DecompilerSettings.UseSdkStyleProjectFormat" xml:space="preserve">
<value>Use new SDK style format for generated project files (*.csproj)</value>
</data>
</root>

3
ILSpy/Properties/Resources.zh-Hans.resx

@ -732,4 +732,7 @@ @@ -732,4 +732,7 @@
<data name="About" xml:space="preserve">
<value>关于</value>
</data>
<data name="DecompilerSettings.UseSdkStyleProjectFormat" xml:space="preserve">
<value>使用新的 SDK 格式 (*.csproj) 生成项目文件</value>
</data>
</root>

2
ILSpy/TextView/DecompilerTextView.cs

@ -45,8 +45,8 @@ using ICSharpCode.AvalonEdit.Highlighting.Xshd; @@ -45,8 +45,8 @@ using ICSharpCode.AvalonEdit.Highlighting.Xshd;
using ICSharpCode.AvalonEdit.Rendering;
using ICSharpCode.AvalonEdit.Search;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.CSharp;
using ICSharpCode.Decompiler.CSharp.OutputVisitor;
using ICSharpCode.Decompiler.CSharp.ProjectDecompiler;
using ICSharpCode.Decompiler.Documentation;
using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.Output;

Loading…
Cancel
Save