commit 709416538bd6d2a26346b9e98c5210a2652a412b
parent 71036bdab7a231cc75c2e551be20106b564c7b19
Author: JohnMcPMS <johnmcp@microsoft.com>
Date: Mon, 30 Mar 2020 14:57:43 -0700
Add a function to check OS version, and leverage it to block installs if MinOSVersion is set and higher than the systems. (#75)
Diffstat:
9 files changed, 159 insertions(+), 3 deletions(-)
diff --git a/src/AppInstallerCLI/AppInstallerCLI.vcxproj b/src/AppInstallerCLI/AppInstallerCLI.vcxproj
@@ -136,6 +136,15 @@
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
<AdditionalDependencies Condition="'$(Configuration)'=='Debug'">wininet.lib;shell32.lib;winsqlite3.lib;shlwapi.lib;icuuc.lib;icuin.lib;urlmon.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
+ <Manifest>
+ <AdditionalManifestFiles Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">$(ProjectDir)..\manifest\shared.manifest %(AdditionalManifestFiles)</AdditionalManifestFiles>
+ </Manifest>
+ <Manifest>
+ <AdditionalManifestFiles Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">$(ProjectDir)..\manifest\shared.manifest %(AdditionalManifestFiles)</AdditionalManifestFiles>
+ </Manifest>
+ <Manifest>
+ <AdditionalManifestFiles Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(ProjectDir)..\manifest\shared.manifest %(AdditionalManifestFiles)</AdditionalManifestFiles>
+ </Manifest>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Platform)'=='Win32'">
<ClCompile>
@@ -143,6 +152,9 @@
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(ProjectDir);..\AppInstallerCLICore\Public\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<TreatWarningAsError Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</TreatWarningAsError>
</ClCompile>
+ <Manifest>
+ <AdditionalManifestFiles Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(ProjectDir)..\manifest\shared.manifest %(AdditionalManifestFiles)</AdditionalManifestFiles>
+ </Manifest>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
<ClCompile>
@@ -166,6 +178,18 @@
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
<AdditionalDependencies Condition="'$(Configuration)'=='Release'">wininet.lib;shell32.lib;winsqlite3.lib;shlwapi.lib;icuuc.lib;icuin.lib;urlmon.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
+ <Manifest>
+ <AdditionalManifestFiles Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">$(ProjectDir)..\manifest\shared.manifest %(AdditionalManifestFiles)</AdditionalManifestFiles>
+ </Manifest>
+ <Manifest>
+ <AdditionalManifestFiles Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">$(ProjectDir)..\manifest\shared.manifest %(AdditionalManifestFiles)</AdditionalManifestFiles>
+ </Manifest>
+ <Manifest>
+ <AdditionalManifestFiles Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(ProjectDir)..\manifest\shared.manifest %(AdditionalManifestFiles)</AdditionalManifestFiles>
+ </Manifest>
+ <Manifest>
+ <AdditionalManifestFiles Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(ProjectDir)..\manifest\shared.manifest %(AdditionalManifestFiles)</AdditionalManifestFiles>
+ </Manifest>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="main.cpp" />
diff --git a/src/AppInstallerCLICore/Workflows/InstallFlow.cpp b/src/AppInstallerCLICore/Workflows/InstallFlow.cpp
@@ -1,6 +1,5 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
-
#include "pch.h"
#include "InstallFlow.h"
#include "ShellExecuteInstallerHandler.h"
@@ -28,8 +27,11 @@ namespace AppInstaller::Workflow
m_reporterRef.ShowMsg("Found app: " + m_searchResult.Matches[0].Application->GetName());
}
- SelectInstaller();
- InstallInternal();
+ if (VerifyOSVersion())
+ {
+ SelectInstaller();
+ InstallInternal();
+ }
}
void InstallFlow::InstallInternal()
@@ -40,6 +42,20 @@ namespace AppInstaller::Workflow
installerHandler->Install();
}
+ bool InstallFlow::VerifyOSVersion()
+ {
+ if (!m_manifest.MinOSVersion.empty() &&
+ !Runtime::IsCurrentOSVersionGreaterThanOrEqual(Version(m_manifest.MinOSVersion)))
+ {
+ m_reporterRef.Error() << "Cannot install application, as it requires a higher OS version: " << m_manifest.MinOSVersion << std::endl;
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+ }
+
std::unique_ptr<InstallerHandlerBase> InstallFlow::GetInstallerHandler()
{
switch (m_selectedInstaller.InstallerType)
diff --git a/src/AppInstallerCLICore/Workflows/InstallFlow.h b/src/AppInstallerCLICore/Workflows/InstallFlow.h
@@ -21,6 +21,9 @@ namespace AppInstaller::Workflow
protected:
void InstallInternal();
+ // Verifies the OS version is capable of supporting the application.
+ bool VerifyOSVersion();
+
// Creates corresponding InstallerHandler according to InstallerType
virtual std::unique_ptr<InstallerHandlerBase> GetInstallerHandler();
};
diff --git a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj
@@ -116,6 +116,9 @@
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
<AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">wininet.lib;shell32.lib;winsqlite3.lib;shlwapi.lib;icuuc.lib;icuin.lib;urlmon.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
+ <Manifest>
+ <AdditionalManifestFiles Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(ProjectDir)..\manifest\shared.manifest</AdditionalManifestFiles>
+ </Manifest>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Platform)'=='Win32'">
<ClCompile>
@@ -126,6 +129,9 @@
<Link>
<AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">wininet.lib;shell32.lib;winsqlite3.lib;shlwapi.lib;icuuc.lib;icuin.lib;urlmon.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
+ <Manifest>
+ <AdditionalManifestFiles Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(ProjectDir)..\manifest\shared.manifest</AdditionalManifestFiles>
+ </Manifest>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
<ClCompile>
@@ -146,6 +152,12 @@
<AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">wininet.lib;shell32.lib;winsqlite3.lib;shlwapi.lib;icuuc.lib;icuin.lib;urlmon.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Release|x64'">wininet.lib;shell32.lib;winsqlite3.lib;shlwapi.lib;icuuc.lib;icuin.lib;urlmon.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
+ <Manifest>
+ <AdditionalManifestFiles Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(ProjectDir)..\manifest\shared.manifest</AdditionalManifestFiles>
+ </Manifest>
+ <Manifest>
+ <AdditionalManifestFiles Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(ProjectDir)..\manifest\shared.manifest</AdditionalManifestFiles>
+ </Manifest>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="pch.h" />
diff --git a/src/AppInstallerCLITests/Versions.cpp b/src/AppInstallerCLITests/Versions.cpp
@@ -2,8 +2,10 @@
// Licensed under the MIT License.
#include "pch.h"
#include "TestCommon.h"
+#include <AppInstallerRuntime.h>
#include <AppInstallerVersions.h>
+using namespace AppInstaller;
using namespace AppInstaller::Utility;
@@ -136,3 +138,12 @@ TEST_CASE("VersionAndChannelSort", "[versions]")
REQUIRE(sortedVAC.GetChannel().ToString() == jumbledVAC.GetChannel().ToString());
}
}
+
+TEST_CASE("MinOsVersion_Check", "[versions]")
+{
+ // Just verify that we are greater than Win 7 and less than far future Win 10.
+ // Unfortunately, an unmanifested process will also pass these validations,
+ // but an unmanifested process also can't use Windows APIs to determine the actual version.
+ REQUIRE(Runtime::IsCurrentOSVersionGreaterThanOrEqual(Version("6.1")));
+ REQUIRE(!Runtime::IsCurrentOSVersionGreaterThanOrEqual(Version("10.0.65535")));
+}
diff --git a/src/AppInstallerCommonCore/Public/AppInstallerRuntime.h b/src/AppInstallerCommonCore/Public/AppInstallerRuntime.h
@@ -1,6 +1,8 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
#pragma once
+#include <AppInstallerVersions.h>
+
#include <filesystem>
#include <memory>
#include <string>
@@ -29,4 +31,8 @@ namespace AppInstaller::Runtime
// Deletes the given setting.
void RemoveSetting(std::filesystem::path name);
+
+ // Determines whether the current OS version is >= the given one.
+ // We treat the given Version struct as a standard 4 part Windows OS version.
+ bool IsCurrentOSVersionGreaterThanOrEqual(const Utility::Version& version);
}
diff --git a/src/AppInstallerCommonCore/Runtime.cpp b/src/AppInstallerCommonCore/Runtime.cpp
@@ -273,6 +273,40 @@ namespace AppInstaller::Runtime
}
}
+ bool IsCurrentOSVersionGreaterThanOrEqual(const Utility::Version& version)
+ {
+ DWORD versionParts[3] = {};
+
+ for (size_t i = 0; i < ARRAYSIZE(versionParts) && i < version.GetParts().size(); ++i)
+ {
+ versionParts[i] = static_cast<DWORD>(std::min(static_cast<decltype(version.GetParts()[i].Integer)>(std::numeric_limits<DWORD>::max()), version.GetParts()[i].Integer));
+ }
+
+ OSVERSIONINFOEXW osVersionInfo{};
+ osVersionInfo.dwOSVersionInfoSize = sizeof(osVersionInfo);
+ osVersionInfo.dwMajorVersion = versionParts[0];
+ osVersionInfo.dwMinorVersion = versionParts[1];
+ osVersionInfo.dwBuildNumber = versionParts[2];
+ osVersionInfo.wServicePackMajor = 0;
+ osVersionInfo.wServicePackMinor = 0;
+
+ DWORD mask = VER_MAJORVERSION | VER_MINORVERSION | VER_BUILDNUMBER | VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR;
+
+ DWORDLONG conditions = 0;
+ VER_SET_CONDITION(conditions, VER_MAJORVERSION, VER_GREATER_EQUAL);
+ VER_SET_CONDITION(conditions, VER_MINORVERSION, VER_GREATER_EQUAL);
+ VER_SET_CONDITION(conditions, VER_BUILDNUMBER, VER_GREATER_EQUAL);
+ VER_SET_CONDITION(conditions, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);
+ VER_SET_CONDITION(conditions, VER_SERVICEPACKMINOR, VER_GREATER_EQUAL);
+
+ BOOL result = VerifyVersionInfoW(&osVersionInfo, mask, conditions);
+ if (!result)
+ {
+ THROW_LAST_ERROR_IF(GetLastError() != ERROR_OLD_WIN_VERSION);
+ }
+ return !!result;
+ }
+
#ifndef AICLI_DISABLE_TEST_HOOKS
void TestHook_ForceContainerPrepend(const std::filesystem::path& prepend)
{
diff --git a/src/AppInstallerSQLiteIndexUtil/AppInstallerSQLiteIndexUtil.vcxproj b/src/AppInstallerSQLiteIndexUtil/AppInstallerSQLiteIndexUtil.vcxproj
@@ -143,6 +143,15 @@
<AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">wininet.lib;shell32.lib;winsqlite3.lib;shlwapi.lib;icuuc.lib;icuin.lib;urlmon.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">wininet.lib;shell32.lib;winsqlite3.lib;shlwapi.lib;icuuc.lib;icuin.lib;urlmon.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
+ <Manifest>
+ <AdditionalManifestFiles Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">$(ProjectDir)..\manifest\shared.manifest %(AdditionalManifestFiles)</AdditionalManifestFiles>
+ </Manifest>
+ <Manifest>
+ <AdditionalManifestFiles Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">$(ProjectDir)..\manifest\shared.manifest %(AdditionalManifestFiles)</AdditionalManifestFiles>
+ </Manifest>
+ <Manifest>
+ <AdditionalManifestFiles Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(ProjectDir)..\manifest\shared.manifest %(AdditionalManifestFiles)</AdditionalManifestFiles>
+ </Manifest>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Platform)'=='Win32'">
<ClCompile>
@@ -155,6 +164,9 @@
<ModuleDefinitionFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Source.def</ModuleDefinitionFile>
<AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">wininet.lib;shell32.lib;winsqlite3.lib;shlwapi.lib;icuuc.lib;icuin.lib;urlmon.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
+ <Manifest>
+ <AdditionalManifestFiles Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(ProjectDir)..\manifest\shared.manifest %(AdditionalManifestFiles)</AdditionalManifestFiles>
+ </Manifest>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
<ClCompile>
@@ -188,6 +200,18 @@
<AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">wininet.lib;shell32.lib;winsqlite3.lib;shlwapi.lib;icuuc.lib;icuin.lib;urlmon.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Release|x64'">wininet.lib;shell32.lib;winsqlite3.lib;shlwapi.lib;icuuc.lib;icuin.lib;urlmon.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
+ <Manifest>
+ <AdditionalManifestFiles Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">$(ProjectDir)..\manifest\shared.manifest %(AdditionalManifestFiles)</AdditionalManifestFiles>
+ </Manifest>
+ <Manifest>
+ <AdditionalManifestFiles Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">$(ProjectDir)..\manifest\shared.manifest %(AdditionalManifestFiles)</AdditionalManifestFiles>
+ </Manifest>
+ <Manifest>
+ <AdditionalManifestFiles Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(ProjectDir)..\manifest\shared.manifest %(AdditionalManifestFiles)</AdditionalManifestFiles>
+ </Manifest>
+ <Manifest>
+ <AdditionalManifestFiles Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(ProjectDir)..\manifest\shared.manifest %(AdditionalManifestFiles)</AdditionalManifestFiles>
+ </Manifest>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="AppInstallerSQLiteIndexUtil.h" />
diff --git a/src/manifest/shared.manifest b/src/manifest/shared.manifest
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
+ <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
+ <application>
+ <!-- Windows 10 -->
+ <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
+ <!-- Windows 8.1 -->
+ <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
+ <!-- Windows 8 -->
+ <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
+ <!-- Windows 7 -->
+ <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
+ </application>
+ </compatibility>
+ <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
+ <security>
+ <requestedPrivileges>
+ <requestedExecutionLevel
+ level="asInvoker"
+ uiAccess="false"
+ />
+ </requestedPrivileges>
+ </security>
+ </trustInfo>
+</assembly>+
\ No newline at end of file