diff --git a/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/IProjectFileWriter.cs b/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/IProjectFileWriter.cs
index d5542fb6e..26c1a8a58 100644
--- a/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/IProjectFileWriter.cs
+++ b/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/IProjectFileWriter.cs
@@ -34,9 +34,8 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler
///
/// The target to write to.
/// The information about the project being created.
- /// 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.
+ /// A collection of source files to be included into the project.
/// The module being decompiled.
- void Write(TextWriter target, IProjectInfoProvider project, IEnumerable<(string itemType, string fileName)> files, PEFile module);
+ void Write(TextWriter target, IProjectInfoProvider project, IEnumerable files, PEFile module);
}
}
diff --git a/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/ProjectFileWriterDefault.cs b/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/ProjectFileWriterDefault.cs
index af98d6045..eb383ba75 100644
--- a/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/ProjectFileWriterDefault.cs
+++ b/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/ProjectFileWriterDefault.cs
@@ -25,6 +25,7 @@ using System.Xml;
using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.Solution;
+using ICSharpCode.Decompiler.Util;
namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler
{
@@ -43,7 +44,7 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler
public void Write(
TextWriter target,
IProjectInfoProvider project,
- IEnumerable<(string itemType, string fileName)> files,
+ IEnumerable files,
PEFile module)
{
const string ns = "http://schemas.microsoft.com/developer/msbuild/2003";
@@ -162,13 +163,18 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler
}
w.WriteEndElement(); // (References)
- foreach (IGrouping gr in from f in files group f.fileName by f.itemType into g orderby g.Key select g)
+ foreach (IGrouping gr in files.GroupBy(f => f.ItemType).OrderBy(g => g.Key))
{
w.WriteStartElement("ItemGroup");
- foreach (string file in gr.OrderBy(f => f, StringComparer.OrdinalIgnoreCase))
+ foreach (var item in gr.OrderBy(f => f.FileName, StringComparer.OrdinalIgnoreCase))
{
w.WriteStartElement(gr.Key);
- w.WriteAttributeString("Include", file);
+ w.WriteAttributeString("Include", item.FileName);
+ if (item.AdditionalProperties != null)
+ {
+ foreach (var (key, value) in item.AdditionalProperties)
+ w.WriteAttributeString(key, value);
+ }
w.WriteEndElement();
}
w.WriteEndElement();
diff --git a/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/ProjectFileWriterSdkStyle.cs b/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/ProjectFileWriterSdkStyle.cs
index 61bb6d21f..b5273f1d5 100644
--- a/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/ProjectFileWriterSdkStyle.cs
+++ b/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/ProjectFileWriterSdkStyle.cs
@@ -66,7 +66,7 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler
public void Write(
TextWriter target,
IProjectInfoProvider project,
- IEnumerable<(string itemType, string fileName)> files,
+ IEnumerable files,
PEFile module)
{
using (XmlTextWriter xmlWriter = new XmlTextWriter(target))
@@ -76,7 +76,7 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler
}
}
- static void Write(XmlTextWriter xml, IProjectInfoProvider project, IEnumerable<(string itemType, string fileName)> files, PEFile module)
+ static void Write(XmlTextWriter xml, IProjectInfoProvider project, IEnumerable files, PEFile module)
{
xml.WriteStartElement("Project");
@@ -188,27 +188,27 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler
}
}
- static void WriteMiscellaneousPropertyGroup(XmlTextWriter xml, IEnumerable<(string itemType, string fileName)> files)
+ static void WriteMiscellaneousPropertyGroup(XmlTextWriter xml, IEnumerable files)
{
- var (itemType, fileName) = files.FirstOrDefault(t => t.itemType == "ApplicationIcon");
+ var (itemType, fileName) = files.FirstOrDefault(t => t.ItemType == "ApplicationIcon");
if (fileName != null)
xml.WriteElementString("ApplicationIcon", fileName);
- (itemType, fileName) = files.FirstOrDefault(t => t.itemType == "ApplicationManifest");
+ (itemType, fileName) = files.FirstOrDefault(t => t.ItemType == "ApplicationManifest");
if (fileName != null)
xml.WriteElementString("ApplicationManifest", fileName);
- if (files.Any(t => t.itemType == "EmbeddedResource"))
+ if (files.Any(t => t.ItemType == "EmbeddedResource"))
xml.WriteElementString("RootNamespace", string.Empty);
// TODO: We should add CustomToolNamespace for resources, otherwise we should add empty RootNamespace
}
- static void WriteResources(XmlTextWriter xml, IEnumerable<(string itemType, string fileName)> files)
+ static void WriteResources(XmlTextWriter xml, IEnumerable files)
{
// remove phase
- foreach (var (itemType, fileName) in files.Where(t => t.itemType == "EmbeddedResource"))
+ foreach (var item in files.Where(t => t.ItemType == "EmbeddedResource"))
{
- string buildAction = Path.GetExtension(fileName).ToUpperInvariant() switch {
+ string buildAction = Path.GetExtension(item.FileName).ToUpperInvariant() switch {
".CS" => "Compile",
".RESX" => "EmbeddedResource",
_ => "None"
@@ -217,18 +217,23 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler
continue;
xml.WriteStartElement(buildAction);
- xml.WriteAttributeString("Remove", fileName);
+ xml.WriteAttributeString("Remove", item.FileName);
xml.WriteEndElement();
}
// include phase
- foreach (var (itemType, fileName) in files.Where(t => t.itemType == "EmbeddedResource"))
+ foreach (var item in files.Where(t => t.ItemType == "EmbeddedResource"))
{
- if (Path.GetExtension(fileName) == ".resx")
+ if (Path.GetExtension(item.FileName) == ".resx")
continue;
xml.WriteStartElement("EmbeddedResource");
- xml.WriteAttributeString("Include", fileName);
+ xml.WriteAttributeString("Include", item.FileName);
+ if (item.AdditionalProperties != null)
+ {
+ foreach (var (key, value) in item.AdditionalProperties)
+ xml.WriteAttributeString(key, value);
+ }
xml.WriteEndElement();
}
}
diff --git a/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/WholeProjectDecompiler.cs b/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/WholeProjectDecompiler.cs
index e342df4a6..852de74a7 100644
--- a/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/WholeProjectDecompiler.cs
+++ b/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/WholeProjectDecompiler.cs
@@ -151,8 +151,8 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler
TargetDirectory = targetDirectory;
directories.Clear();
var resources = WriteResourceFilesInProject(moduleDefinition).ToList();
- var files = WriteCodeFilesInProject(moduleDefinition, resources.SelectMany(r => r.partialTypes ?? Enumerable.Empty()).ToList(), cancellationToken).ToList();
- files.AddRange(resources.Select(r => (r.itemType, r.fileName)));
+ var files = WriteCodeFilesInProject(moduleDefinition, resources.SelectMany(r => r.PartialTypes ?? Enumerable.Empty()).ToList(), cancellationToken).ToList();
+ files.AddRange(resources);
files.AddRange(WriteMiscellaneousFilesInProject(moduleDefinition));
if (StrongNameKeyFile != null)
{
@@ -190,7 +190,7 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler
return decompiler;
}
- IEnumerable<(string itemType, string fileName)> WriteAssemblyInfo(DecompilerTypeSystem ts, CancellationToken cancellationToken)
+ IEnumerable WriteAssemblyInfo(DecompilerTypeSystem ts, CancellationToken cancellationToken)
{
var decompiler = CreateDecompiler(ts);
decompiler.CancellationToken = cancellationToken;
@@ -205,10 +205,10 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler
{
syntaxTree.AcceptVisitor(new CSharpOutputVisitor(w, Settings.CSharpFormattingOptions));
}
- return new[] { ("Compile", assemblyInfo) };
+ return new[] { new ProjectItemInfo("Compile", assemblyInfo) };
}
- IEnumerable<(string itemType, string fileName)> WriteCodeFilesInProject(Metadata.PEFile module, IList partialTypes, CancellationToken cancellationToken)
+ IEnumerable WriteCodeFilesInProject(Metadata.PEFile module, IList partialTypes, CancellationToken cancellationToken)
{
var metadata = module.Metadata;
var files = module.Metadata.GetTopLevelTypeDefinitions().Where(td => IncludeTypeWhenDecompilingProject(module, td))
@@ -229,7 +229,7 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler
progress.TotalUnits = files.Count;
}
- return files.Select(f => ("Compile", f.Key)).Concat(WriteAssemblyInfo(ts, cancellationToken));
+ return files.Select(f => new ProjectItemInfo("Compile", f.Key)).Concat(WriteAssemblyInfo(ts, cancellationToken));
string GetFileFileNameForHandle(TypeDefinitionHandle h)
{
@@ -308,7 +308,7 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler
#endregion
#region WriteResourceFilesInProject
- protected virtual IEnumerable<(string itemType, string fileName, List partialTypes)> WriteResourceFilesInProject(Metadata.PEFile module)
+ protected virtual IEnumerable WriteResourceFilesInProject(Metadata.PEFile module)
{
foreach (var r in module.Resources.Where(r => r.ResourceType == ResourceType.Embedded))
{
@@ -318,7 +318,7 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler
if (r.Name.EndsWith(".resources", StringComparison.OrdinalIgnoreCase))
{
bool decodedIntoIndividualFiles;
- var individualResources = new List<(string itemType, string fileName, List partialTypes)>();
+ var individualResources = new List();
try
{
var resourcesFile = new ResourcesFile(stream);
@@ -378,12 +378,12 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler
stream.Position = 0;
stream.CopyTo(fs);
}
- yield return ("EmbeddedResource", fileName, null);
+ yield return new ProjectItemInfo("EmbeddedResource", fileName).With("LogicalName", r.Name);
}
}
}
- protected virtual IEnumerable<(string itemType, string fileName, List partialTypes)> WriteResourceToFile(string fileName, string resourceName, Stream entryStream)
+ protected virtual IEnumerable WriteResourceToFile(string fileName, string resourceName, Stream entryStream)
{
if (fileName.EndsWith(".resources", StringComparison.OrdinalIgnoreCase))
{
@@ -398,7 +398,7 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler
writer.AddResource(entry.Key, entry.Value);
}
}
- return new[] { ("EmbeddedResource", resx, (List)null) };
+ return new[] { new ProjectItemInfo("EmbeddedResource", resx).With("LogicalName", resourceName) };
}
catch (BadImageFormatException)
{
@@ -413,7 +413,7 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler
{
entryStream.CopyTo(fs);
}
- return new[] { ("EmbeddedResource", fileName, (List)null) };
+ return new[] { new ProjectItemInfo("EmbeddedResource", fileName).With("LogicalName", resourceName) };
}
string GetFileNameForResource(string fullName)
@@ -444,7 +444,7 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler
#endregion
#region WriteMiscellaneousFilesInProject
- protected virtual IEnumerable<(string itemType, string fileName)> WriteMiscellaneousFilesInProject(PEFile module)
+ protected virtual IEnumerable WriteMiscellaneousFilesInProject(PEFile module)
{
var resources = module.Reader.ReadWin32Resources();
if (resources == null)
@@ -454,21 +454,21 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler
if (appIcon != null)
{
File.WriteAllBytes(Path.Combine(TargetDirectory, "app.ico"), appIcon);
- yield return ("ApplicationIcon", "app.ico");
+ yield return new ProjectItemInfo("ApplicationIcon", "app.ico");
}
byte[] appManifest = CreateApplicationManifest(resources);
if (appManifest != null && !IsDefaultApplicationManifest(appManifest))
{
File.WriteAllBytes(Path.Combine(TargetDirectory, "app.manifest"), appManifest);
- yield return ("ApplicationManifest", "app.manifest");
+ yield return new ProjectItemInfo("ApplicationManifest", "app.manifest");
}
var appConfig = module.FileName + ".config";
if (File.Exists(appConfig))
{
File.Copy(appConfig, Path.Combine(TargetDirectory, "app.config"), overwrite: true);
- yield return ("ApplicationConfig", Path.GetFileName(appConfig));
+ yield return new ProjectItemInfo("ApplicationConfig", Path.GetFileName(appConfig));
}
}
@@ -753,4 +753,25 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler
return TargetServices.DetectTargetFramework(module).Moniker != null;
}
}
+
+ public record struct ProjectItemInfo(string ItemType, string FileName)
+ {
+ public List PartialTypes { get; set; } = null;
+
+ public Dictionary AdditionalProperties { get; set; } = null;
+
+ public ProjectItemInfo With(string name, string value)
+ {
+ AdditionalProperties ??= new Dictionary();
+ AdditionalProperties.Add(name, value);
+ return this;
+ }
+
+ public ProjectItemInfo With(IEnumerable> pairs)
+ {
+ AdditionalProperties ??= new Dictionary();
+ AdditionalProperties.AddRange(pairs);
+ return this;
+ }
+ }
}
diff --git a/ILSpy.BamlDecompiler/BamlResourceNodeFactory.cs b/ILSpy.BamlDecompiler/BamlResourceNodeFactory.cs
index be0a6ae1c..4ac408de5 100644
--- a/ILSpy.BamlDecompiler/BamlResourceNodeFactory.cs
+++ b/ILSpy.BamlDecompiler/BamlResourceNodeFactory.cs
@@ -72,6 +72,8 @@ namespace ILSpy.BamlDecompiler
{
fileName = Path.ChangeExtension(fileName, ".xaml");
}
+ context.AdditionalProperties.Add("Generator", "MSBuild:Compile");
+ context.AdditionalProperties.Add("SubType", "Designer");
string saveFileName = Path.Combine(context.DecompilationOptions.SaveAsProjectDirectory, fileName);
Directory.CreateDirectory(Path.GetDirectoryName(saveFileName));
result.Xaml.Save(saveFileName);
diff --git a/ILSpy/Languages/CSharpLanguage.cs b/ILSpy/Languages/CSharpLanguage.cs
index 703fcd3a6..a5cd1e1a0 100644
--- a/ILSpy/Languages/CSharpLanguage.cs
+++ b/ILSpy/Languages/CSharpLanguage.cs
@@ -517,7 +517,7 @@ namespace ICSharpCode.ILSpy
this.options = options;
}
- protected override IEnumerable<(string itemType, string fileName, List partialTypes)> WriteResourceToFile(string fileName, string resourceName, Stream entryStream)
+ protected override IEnumerable WriteResourceToFile(string fileName, string resourceName, Stream entryStream)
{
var context = new ResourceFileHandlerContext(options);
foreach (var handler in App.ExportProvider.GetExportedValues())
@@ -527,7 +527,7 @@ namespace ICSharpCode.ILSpy
entryStream.Position = 0;
fileName = handler.WriteResourceToFile(assembly, fileName, entryStream, context);
- return new[] { (handler.EntryType, fileName, context.PartialTypes) };
+ return new[] { new ProjectItemInfo(handler.EntryType, fileName) { PartialTypes = context.PartialTypes }.With(context.AdditionalProperties) };
}
}
return base.WriteResourceToFile(fileName, resourceName, entryStream);
diff --git a/ILSpy/Languages/IResourceFileHandler.cs b/ILSpy/Languages/IResourceFileHandler.cs
index 8fe336f06..19b977ac5 100644
--- a/ILSpy/Languages/IResourceFileHandler.cs
+++ b/ILSpy/Languages/IResourceFileHandler.cs
@@ -36,6 +36,9 @@ namespace ICSharpCode.ILSpy
readonly List partialTypes = new();
internal List PartialTypes => partialTypes;
+ readonly Dictionary additionalProperties = new();
+ public Dictionary AdditionalProperties => additionalProperties;
+
public DecompilationOptions DecompilationOptions { get; }
public ResourceFileHandlerContext(DecompilationOptions options)