diff --git a/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/ProjectFileWriterDefault.cs b/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/ProjectFileWriterDefault.cs index 2e5a61ba1..fe131f06a 100644 --- a/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/ProjectFileWriterDefault.cs +++ b/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/ProjectFileWriterDefault.cs @@ -49,6 +49,8 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler const string ns = "http://schemas.microsoft.com/developer/msbuild/2003"; string platformName = TargetServices.GetPlatformName(module); var targetFramework = TargetServices.DetectTargetFramework(module); + if (targetFramework.Identifier == ".NETFramework" && targetFramework.VersionNumber == 200) + targetFramework = TargetServices.DetectTargetFrameworkNET20(module, project.AssemblyResolver, targetFramework); List typeGuids = new List(); if (targetFramework.IsPortableClassLibrary) diff --git a/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/ProjectFileWriterSdkStyle.cs b/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/ProjectFileWriterSdkStyle.cs index 98815acf3..1d50f28db 100644 --- a/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/ProjectFileWriterSdkStyle.cs +++ b/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/ProjectFileWriterSdkStyle.cs @@ -83,7 +83,7 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler var projectType = GetProjectType(module); xml.WriteAttributeString("Sdk", GetSdkString(projectType)); - PlaceIntoTag("PropertyGroup", xml, () => WriteAssemblyInfo(xml, module, projectType)); + PlaceIntoTag("PropertyGroup", xml, () => WriteAssemblyInfo(xml, module, project, projectType)); PlaceIntoTag("PropertyGroup", xml, () => WriteProjectInfo(xml, project)); PlaceIntoTag("ItemGroup", xml, () => WriteReferences(xml, module, project)); @@ -103,7 +103,7 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler } } - static void WriteAssemblyInfo(XmlTextWriter xml, PEFile module, ProjectType projectType) + static void WriteAssemblyInfo(XmlTextWriter xml, PEFile module, IProjectInfoProvider project, ProjectType projectType) { xml.WriteElementString("AssemblyName", module.Name); @@ -120,6 +120,8 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler string platformName = TargetServices.GetPlatformName(module); var targetFramework = TargetServices.DetectTargetFramework(module); + if (targetFramework.Identifier == ".NETFramework" && targetFramework.VersionNumber == 200) + targetFramework = TargetServices.DetectTargetFrameworkNET20(module, project.AssemblyResolver, targetFramework); if (targetFramework.Moniker == null) { diff --git a/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/TargetServices.cs b/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/TargetServices.cs index a1a0fc47f..05ab9f721 100644 --- a/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/TargetServices.cs +++ b/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/TargetServices.cs @@ -17,6 +17,7 @@ // DEALINGS IN THE SOFTWARE. using System; +using System.Collections.Generic; using System.Linq; using System.Reflection.PortableExecutable; @@ -58,7 +59,6 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler case TargetRuntime.Net_2_0: versionNumber = 200; - // TODO: Detect when .NET 3.0/3.5 is required break; default: @@ -133,5 +133,131 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler return architecture.ToString(); } } + + static HashSet dotNet30Assemblies = new HashSet(StringComparer.OrdinalIgnoreCase) { + // System + "System.IdentityModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", + "System.IdentityModel.Selectors, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", + "System.IO.Log, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", + "System.Printing, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35", + "System.Runtime.Serialization, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", + "System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", + "System.ServiceModel.Install, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", + "System.ServiceModel.WasHosting, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", + "System.Speech, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35", + "System.Workflow.Activities, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35", + "System.Workflow.ComponentModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35", + "System.Workflow.Runtime, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35", + + // WPF + "PresentationBuildTasks, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35", + "PresentationCFFRasterizer, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35", + "PresentationCore, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35", + "PresentationFramework, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35", + "PresentationFramework.Aero, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35", + "PresentationFramework.Classic, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35", + "PresentationFramework.Luna, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35", + "PresentationFramework.Royale, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35", + "PresentationUI, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35", + "ReachFramework, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35", + "WindowsBase, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35", + + // UIAutomation + "WindowsFormsIntegration, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35", + "UIAutomationClient, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35", + "UIAutomationClientsideProviders, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35", + "UIAutomationProvider, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35", + "UIAutomationTypes, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35", + + // WCF + "Microsoft.Transactions.Bridge, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", + "Microsoft.Transactions.Bridge.Dtc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", + }; + + static HashSet dotNet35Assemblies = new HashSet(StringComparer.OrdinalIgnoreCase) { + // System + "System.AddIn, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", + "System.AddIn.Contract, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", + "System.ComponentModel.DataAnnotations, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35", + "System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", + "System.Data.DataSetExtensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", + "System.Data.Entity, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", + "System.Data.Entity.Design, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", + "System.Data.Linq, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", + "System.Data.Services, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", + "System.Data.Services.Client, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", + "System.Data.Services.Design, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", + "System.DirectoryServices.AccountManagement, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", + "System.Management.Instrumentation, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", + "System.Net, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", + "System.ServiceModel.Web, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35", + "System.Web.Abstractions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35", + "System.Web.DynamicData, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35", + "System.Web.DynamicData.Design, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35", + "System.Web.Entity, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", + "System.Web.Entity.Design, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", + "System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35", + "System.Web.Extensions.Design, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35", + "System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35", + "System.Windows.Presentation, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", + "System.WorkflowServices, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35", + "System.Xml.Linq, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", + + // MSBuild + "Microsoft.Build.Conversion.v3.5, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", + "Microsoft.Build.Engine, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", + "Microsoft.Build.Framework, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", + "Microsoft.Build.Tasks.v3.5, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", + "Microsoft.Build.Utilities.v3.5, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", + "Microsoft.Data.Entity.Build.Tasks, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", + }; + + /// + /// Gets exact if is + /// + public static TargetFramework DetectTargetFrameworkNET20(PEFile module, IAssemblyResolver assemblyResolver, TargetFramework targetFramework) + { + var resolvedAssemblies = new HashSet(); + int version = 200; + GetFrameworkVersionNET20(module, assemblyResolver, resolvedAssemblies, ref version); + return new TargetFramework(targetFramework.Identifier, version, targetFramework.Profile); + } + + static void GetFrameworkVersionNET20(PEFile module, IAssemblyResolver assemblyResolver, HashSet resolvedAssemblies, ref int version) + { + foreach (var r in module.Metadata.AssemblyReferences) + { + var reference = new AssemblyReference(module, r); + if (!resolvedAssemblies.Add(reference.FullName)) + continue; + + if (dotNet30Assemblies.Contains(reference.FullName)) + { + version = 300; + continue; + } + else if (dotNet35Assemblies.Contains(reference.FullName)) + { + version = 350; + break; + } + + PEFile resolvedReference; + try + { + resolvedReference = assemblyResolver.Resolve(reference); + } + catch (AssemblyResolutionException) + { + resolvedReference = null; + } + if (resolvedReference == null) + continue; + resolvedAssemblies.Add(resolvedReference.FullName); + GetFrameworkVersionNET20(resolvedReference, assemblyResolver, resolvedAssemblies, ref version); + if (version == 350) + return; + } + } } } diff --git a/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/WholeProjectDecompiler.cs b/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/WholeProjectDecompiler.cs index 2c3270c2a..1ad283b97 100644 --- a/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/WholeProjectDecompiler.cs +++ b/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/WholeProjectDecompiler.cs @@ -205,7 +205,7 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler } else { - string dir = CleanUpFileName(metadata.GetString(type.Namespace)); + string dir = CleanUpDirectoryName(metadata.GetString(type.Namespace)); if (directories.Add(dir)) Directory.CreateDirectory(Path.Combine(TargetDirectory, dir)); return Path.Combine(dir, file); @@ -403,6 +403,40 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler return name; } + /// + /// Cleans up a node name for use as a directory name. + /// + public static string CleanUpDirectoryName(string text) + { + int pos = text.IndexOf(':'); + if (pos > 0) + text = text.Substring(0, pos); + pos = text.IndexOf('`'); + if (pos > 0) + text = text.Substring(0, pos); + text = text.Trim(); + // Whitelist allowed characters, replace everything else: + StringBuilder b = new StringBuilder(text.Length); + foreach (var c in text) + { + if (char.IsLetterOrDigit(c) || c == '-' || c == '_' || c == '\\') + b.Append(c); + else if (c == '.' && b.Length > 0 && b[b.Length - 1] != '.') + b.Append('\\'); // allow dot, but never two in a row + else + b.Append('-'); + if (b.Length >= 200) + break; // limit to 200 chars + } + if (b.Length == 0) + b.Append('-'); + string name = b.ToString(); + if (name == ".") + return "_"; + else + return name; + } + static bool IsReservedFileSystemName(string name) { switch (name.ToUpperInvariant())