Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,7 @@ private bool IsSupportedOutputType(ProjectOutputType type) =>
ProjectOutputType.Library => true,
ProjectOutputType.WinExe => true,
ProjectOutputType.AppContainerExe => true,
ProjectOutputType.WinMdObj => true,
_ => false
};

Expand Down Expand Up @@ -295,6 +296,10 @@ private ProjectOutputType GetProjectOutputType(IProjectRootElement root, Project
{
return ProjectOutputType.AppContainerExe;
}
else if (ProjectPropertyHelpers.IsWinMdObjProjectType(outputTypeNode))
{
return ProjectOutputType.WinMdObj;
}
else
{
return ProjectOutputType.Other;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public enum ProjectOutputType
Exe,
WinExe,
AppContainerExe,
WinMdObj,
Other,
None
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,13 @@ public static bool IsWinExeOutputType(ProjectPropertyElement prop) =>
prop.ElementName.Equals(MSBuildFacts.OutputTypeNodeName, StringComparison.OrdinalIgnoreCase)
&& prop.Value.Equals(MSBuildFacts.WinExeOutputType, StringComparison.OrdinalIgnoreCase);

/// <summary>
/// Checks if an OutputType node is WinMdObj.
/// </summary>
public static bool IsWinMdObjProjectType(ProjectPropertyElement prop) =>
prop.ElementName.Equals(MSBuildFacts.OutputTypeNodeName, StringComparison.OrdinalIgnoreCase)
&& prop.Value.Equals(MSBuildFacts.WinMdObjOutputType, StringComparison.OrdinalIgnoreCase);

public static bool IsVisualBasicProject(ProjectPropertyElement prop) =>
IsProjectTypeGuidsNode(prop) && prop.Value.Split(';').Any(guidString => Guid.Parse(guidString) == MSBuildFacts.LanguageProjectTypeVisualBasic);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,7 @@ public static class MSBuildFacts
public const string ExeOutputType = "Exe";
public const string WinExeOutputType = "WinExe";
public const string AppContainerExeOutputType = "AppContainerExe";
public const string WinMdObjOutputType = "winmdobj";
public const string NuGetPackageImportStampNodeName = "NuGetPackageImportStamp";
public const string ReferencePathNodeName = "ReferencePath";
public const string LegacyTargetFrameworkPropertyNodeName = "TargetFrameworkIdentifier";
Expand All @@ -311,5 +312,7 @@ public static class MSBuildFacts
public const string TargetPlatformIdentifierNodeName = "TargetPlatformIdentifier";
public const string UapValue = "UAP";
public const string TargetPlatformVersionNodeName = "TargetPlatformVersion";
public const string CsWinRTComponentName = "CsWinRTComponent";
public static readonly (string Name, string Version) CsWinRTPackageReference = (Name: "Microsoft.Windows.CsWinRT", Version: "1.6.4");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ public void Convert(string outputPath)

// Now we can convert the project over
.ChangeImportsAndAddSdkAttribute(_sdkBaselineProject, _forceRemoveCustomImports)
.AddCsWinRTReferenceAndComponentProperty(_sdkBaselineProject)
.UpdateOutputTypeProperty(_sdkBaselineProject)
.RemoveDefaultedProperties(_sdkBaselineProject, _differs)
.RemoveUnnecessaryPropertiesNotInSDKByDefault(_sdkBaselineProject.ProjectStyle)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,21 @@ public static IProjectRootElement ChangeImportsAndAddSdkAttribute(this IProjectR
return projectRootElement;
}

public static IProjectRootElement AddCsWinRTReferenceAndComponentProperty(this IProjectRootElement projectRootElement, BaselineProject baselineProject)
{
if (baselineProject.OutputType == ProjectOutputType.WinMdObj)
{
var topLevelPropGroup = MSBuildHelpers.GetOrCreateTopLevelPropertyGroup(baselineProject, projectRootElement);
topLevelPropGroup.AddProperty(MSBuildFacts.CsWinRTComponentName, "true");

var packageReferenceItemGroup = projectRootElement.ItemGroups.Where(ig => ig.Items.Any(i => i.ItemType == MSBuildFacts.MSBuildPackageReferenceName))
.FirstOrDefault() ?? projectRootElement.AddItemGroup();
AddPackageReferenceElement(packageReferenceItemGroup, MSBuildFacts.CsWinRTPackageReference.Name, MSBuildFacts.CsWinRTPackageReference.Version);
}

return projectRootElement;
}

public static IProjectRootElement UpdateOutputTypeProperty(this IProjectRootElement projectRootElement, BaselineProject baselineProject)
{
var outputTypeNode = projectRootElement.GetOutputTypeNode();
Expand All @@ -79,6 +94,7 @@ public static IProjectRootElement UpdateOutputTypeProperty(this IProjectRootElem
ProjectOutputType.Library => MSBuildFacts.LibraryOutputType,
ProjectOutputType.WinExe => MSBuildFacts.WinExeOutputType,
ProjectOutputType.AppContainerExe => MSBuildFacts.WinExeOutputType,
ProjectOutputType.WinMdObj => MSBuildFacts.LibraryOutputType,
_ => throw new InvalidOperationException("Unsupported output type: " + baselineProject.OutputType)
};
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Microsoft.DotNet.UpgradeAssistant.Extensions.Windows.UWPtoWinAppSDKUpgrade.Utils
{
public static class IProjectExtensions
{
public static IEnumerable<string> AllProjectReferences(this IProject project) => project.GetRoslynProject().AllProjectReferences.Select(projRef => projRef.ProjectId.ToString());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;

namespace Microsoft.DotNet.UpgradeAssistant.Extensions.Windows.UWPtoWinAppSDKUpgrade
namespace Microsoft.DotNet.UpgradeAssistant.Extensions.Windows.UWPtoWinAppSDKUpgrade.Utils
{
internal static class UWPToWinUIHelpers
internal static class SyntaxNodeExtensions
{
public static IEnumerable<string> GetAllImportedNamespaces(this SyntaxNode node)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.DotNet.UpgradeAssistant.Extensions.Windows.UWPtoWinAppSDKUpgrade;
using Microsoft.DotNet.UpgradeAssistant.Extensions.Windows.UWPtoWinAppSDKUpgrade.Abstractions;
using Microsoft.DotNet.UpgradeAssistant.Extensions.Windows.UWPtoWinAppSDKUpgrade.Utils;

namespace Microsoft.DotNet.UpgradeAssistant.Extensions.Windows
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.DotNet.UpgradeAssistant.Extensions.Windows.UWPtoWinAppSDKUpgrade;
using Microsoft.DotNet.UpgradeAssistant.Extensions.Windows.UWPtoWinAppSDKUpgrade.Utils;

namespace Microsoft.DotNet.UpgradeAssistant.Extensions.Windows
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.DotNet.UpgradeAssistant.Extensions.Windows.UWPtoWinAppSDKUpgrade;
using Microsoft.DotNet.UpgradeAssistant.Extensions.Windows.UWPtoWinAppSDKUpgrade.Utils;

namespace Microsoft.DotNet.UpgradeAssistant.Extensions.Windows
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.DotNet.UpgradeAssistant.Extensions.Windows.UWPtoWinAppSDKUpgrade.Utils;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;

Expand All @@ -18,6 +21,12 @@ public class WinUIPropertiesUpdater : IUpdater<IProject>
{
public const string RuleID = "UA302";

private const string CsWinRTLogMessageFormat = "A CsWinRTIncludes property with value {0} has been added to specify the namespace of the referenced vcxproj component to project..\n" +
"If your project assembly name differs from {0}, update this value with the assembly name.\n" +
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this message printed for the component scenario where the project assembly name comes into play or is it printed for the vcxproj references scenario?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is printed for all the vcxproj scenarios (There seems to be no good way to parse the assembly name as we are unable to load cpp projects). So, whenever we add a CsWinRTIncludes property with the name same as the vcxproj file name, we show this message on the console.

"Read more about C#/WinRT here: https://docs.microsoft.com/en-us/windows/apps/develop/platform/csharp-winrt/";

private const string CsWinRTIncludesProperty = "CsWinRTIncludes";

public string Id => typeof(WinUIPropertiesUpdater).FullName;

public string Title => "Update WinUI Project Properties";
Expand Down Expand Up @@ -69,6 +78,19 @@ public async Task<IUpdaterResult> ApplyAsync(IUpgradeContext context, ImmutableA
}
}

foreach (var projRef in project.AllProjectReferences())
{
if (projRef.Contains(".vcxproj"))
{
var projectName = ParseProjectNameWithExtension(projRef, ".vcxproj");
var csWinRTIncludesValue = projectFile.GetPropertyValue(CsWinRTIncludesProperty) ?? string.Empty;
var delimiter = csWinRTIncludesValue.Trim().Length == 0 || csWinRTIncludesValue.EndsWith(";") ? string.Empty : ";";
projectFile.SetPropertyValue(CsWinRTIncludesProperty, $"{csWinRTIncludesValue}{delimiter}{projectName}");

_logger.LogInformation(string.Format(CsWinRTLogMessageFormat, projectName));
}
}

projectFile.AddItem(new ProjectItemDescriptor(ProjectItemType.Compile) { Remove = "App.xaml.old.cs" });
projectFile.AddItem(new ProjectItemDescriptor(ProjectItemType.None) { Include = "App.xaml.old.cs" });
projectFile.RemoveItem(new ProjectItemDescriptor(ProjectItemType.Content) { Include = "Properties\\Default.rd.xml" });
Expand All @@ -85,6 +107,25 @@ public async Task<IUpdaterResult> ApplyAsync(IUpgradeContext context, ImmutableA
new List<string>());
}

/*
This function parses the project name from projectReference string which includes the file path, project id and more text.
It does so by finding the position of ".vcxproj" in the string and then reading the name backwards character by character
until the first non-alphanumeric character.
*/
private string ParseProjectNameWithExtension(string projectReference, string extension)
Comment thread
ujjwalchadha marked this conversation as resolved.
{
var index = projectReference.IndexOf(".vcxproj");
index--;
StringBuilder sb = new StringBuilder();
Comment thread
ujjwalchadha marked this conversation as resolved.
while (index > -1 && char.IsLetterOrDigit(projectReference[index]))
{
sb.Append(projectReference[index]);
index--;
}

return new string(sb.ToString().Reverse().ToArray());
}

public async Task<IUpdaterResult> IsApplicableAsync(IUpgradeContext context, ImmutableArray<IProject> inputs, CancellationToken token)
{
await Task.Yield();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@
using System.Collections.Immutable;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.DotNet.UpgradeAssistant.Dependencies;
using Microsoft.DotNet.UpgradeAssistant.Extensions.Windows.UWPtoWinAppSDKUpgrade.Utils;
using Microsoft.Extensions.Logging;

namespace Microsoft.DotNet.UpgradeAssistant.Extensions.Windows.UWPtoWinAppSDKUpgrade
Expand All @@ -18,6 +20,9 @@ internal class WinUIReferenceAnalyzer : IDependencyAnalyzer
{
public string Name => "Windows App SDK package analysis";

private const string CsWinRTPackageName = "Microsoft.Windows.CsWinRT";
private const string CsWinRTVersion = "1.6.4";

private readonly IPackageLoader _packageLoader;
private readonly ILogger _logger;

Expand All @@ -34,6 +39,13 @@ public async Task AnalyzeAsync(IProject project, IDependencyAnalysisState state,
return;
}

if (project.AllProjectReferences().Any(id => id.Contains(".vcxproj")))
{
var newPackage = new NuGetReference(CsWinRTPackageName, CsWinRTVersion);
state.Packages.Add(newPackage,
new OperationDetails() { Risk = BuildBreakRisk.Medium, Details = ImmutableList.Create<string>(newPackage.Name) });
}

foreach (var package in state.Packages)
{
if (package.Name.StartsWith("Microsoft.Toolkit", StringComparison.Ordinal))
Expand Down