Skip to content

Commit dab7930

Browse files
committed
windows: generate app manifests for all exe projects
Automatically generate the correct application manifest for Windows executable projects that we produce. The manifests are required on Windows systems newer than Windows 8 to correctly access versioning APIs that will otherwise always report "Windows 8", even on later versions. The manifest we generate states we are compatible with all versions of Windows from 7 to 11 (inclusive).
1 parent f128d21 commit dab7930

File tree

5 files changed

+113
-0
lines changed

5 files changed

+113
-0
lines changed

Directory.Build.props

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@
1818
<RepoSrcPath>$(RepoPath)src\</RepoSrcPath>
1919
<RepoOutPath>$(RepoPath)out\</RepoOutPath>
2020
<RepoAssetsPath>$(RepoPath)assets\</RepoAssetsPath>
21+
22+
<!-- Identify projects that output an executable binary (not libraries) -->
23+
<_IsExeProject Condition="'$(OutputType)' == 'Exe' OR '$(OutputType)' == 'WinExe'">true</_IsExeProject>
24+
25+
<!-- Automatically generate a Windows app manifest on Windows for exe projects -->
26+
<GenerateWindowsAppManifest Condition="'$(GenerateWindowsAppManifest)' == '' AND '$(OSPlatform)' == 'windows' AND '$(_IsExeProject)' == 'true'">true</GenerateWindowsAppManifest>
2127
</PropertyGroup>
2228

2329
<ItemGroup>

Directory.Build.targets

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3+
<!-- This is the root Directory.Build.targets file -->
4+
5+
<!-- Load custom build tasks -->
6+
<Import Project="$(RepoPath)build\GCM.tasks" />
7+
8+
<!-- Windows application manifest generation -->
9+
<PropertyGroup Condition="'$(GenerateWindowsAppManifest)' != 'false'">
10+
<ApplicationManifest>$(IntermediateOutputPath)app.manifest</ApplicationManifest>
11+
</PropertyGroup>
12+
13+
<!-- Generate the manifest file before we set the win32 manifest properties -->
14+
<Target Name="GenerateWindowsAppManifest"
15+
BeforeTargets="SetWin32ManifestProperties"
16+
Condition="'$(GenerateWindowsAppManifest)' != 'false'"
17+
Inputs="$(FileVersion);$(AssemblyName)"
18+
Outputs="$(IntermediateOutputPath)app.manifest">
19+
<GenerateWindowsAppManifest Version="$(FileVersion)"
20+
ApplicationName="$(AssemblyName)"
21+
OutputFile="$(IntermediateOutputPath)app.manifest"/>
22+
<ItemGroup>
23+
<FileWrites Include="$(IntermediateOutputPath)app.manifest" />
24+
</ItemGroup>
25+
</Target>
26+
27+
</Project>

build/GCM.MSBuild.csproj

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>netstandard2.0</TargetFramework>
5+
<IncludeBuildOutput>false</IncludeBuildOutput>
6+
</PropertyGroup>
7+
8+
<ItemGroup>
9+
<PackageReference Include="Microsoft.Build.Framework" Version="16.0.461" PrivateAssets="all" />
10+
<PackageReference Include="Microsoft.Build.Utilities.Core" Version="16.0.461" PrivateAssets="all" />
11+
</ItemGroup>
12+
13+
</Project>

build/GCM.tasks

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<Project>
2+
<PropertyGroup Condition="'$(MSBuildRuntimeType)' == 'Mono'">
3+
<_TaskAssembly>$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll</_TaskAssembly>
4+
<_TaskFactory>CodeTaskFactory</_TaskFactory>
5+
</PropertyGroup>
6+
<PropertyGroup Condition="'$(MSBuildRuntimeType)' != 'Mono'">
7+
<_TaskAssembly>$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll</_TaskAssembly>
8+
<_TaskFactory>RoslynCodeTaskFactory</_TaskFactory>
9+
</PropertyGroup>
10+
11+
<UsingTask TaskName="GenerateWindowsAppManifest" TaskFactory="$(_TaskFactory)" AssemblyFile="$(_TaskAssembly)">
12+
<Task>
13+
<Code Type="Class" Source="$(MSBuildThisFileDirectory)GenerateWindowsAppManifest.cs" />
14+
</Task>
15+
</UsingTask>
16+
</Project>

build/GenerateWindowsAppManifest.cs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
using Microsoft.Build.Framework;
2+
using Microsoft.Build.Utilities;
3+
using System.IO;
4+
5+
namespace GitCredentialManager.MSBuild
6+
{
7+
public class GenerateWindowsAppManifest : Task
8+
{
9+
[Required]
10+
public string Version { get; set; }
11+
12+
[Required]
13+
public string ApplicationName { get; set; }
14+
15+
[Required]
16+
public string OutputFile { get; set; }
17+
18+
public override bool Execute()
19+
{
20+
Log.LogMessage(MessageImportance.Normal, "Creating application manifest file for '{0}'...", ApplicationName);
21+
22+
string manifestDirectory = Path.GetDirectoryName(OutputFile);
23+
if (!Directory.Exists(manifestDirectory))
24+
{
25+
Directory.CreateDirectory(manifestDirectory);
26+
}
27+
28+
File.WriteAllText(
29+
OutputFile,
30+
$@"<?xml version=""1.0"" encoding=""utf-8""?>
31+
<assembly manifestVersion=""1.0"" xmlns=""urn:schemas-microsoft-com:asm.v1"">
32+
<assemblyIdentity version=""{Version}"" name=""{ApplicationName}""/>
33+
<compatibility xmlns=""urn:schemas-microsoft-com:compatibility.v1"">
34+
<application>
35+
<!-- Windows 10 and Windows 11 -->
36+
<supportedOS Id=""{{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}}""/>
37+
<!-- Windows 8.1 -->
38+
<supportedOS Id=""{{1f676c76-80e1-4239-95bb-83d0f6d0da78}}""/>
39+
<!-- Windows 8 -->
40+
<supportedOS Id=""{{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}}""/>
41+
<!-- Windows 7 -->
42+
<supportedOS Id=""{{35138b9a-5d96-4fbd-8e2d-a2440225f93a}}""/>
43+
</application>
44+
</compatibility>
45+
</assembly>
46+
");
47+
48+
return true;
49+
}
50+
}
51+
}

0 commit comments

Comments
 (0)