winget-cli

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

Runtime.cpp (7427B)


      1 // Copyright (c) Microsoft Corporation.
      2 // Licensed under the MIT License.
      3 #include "pch.h"
      4 #include <binver/version.h>
      5 #include "Public/winget/Runtime.h"
      6 #include "Public/AppInstallerLogging.h"
      7 #include "Public/AppInstallerStrings.h"
      8 
      9 
     10 namespace AppInstaller::Runtime
     11 {
     12     using namespace Utility;
     13 
     14     namespace
     15     {
     16         using namespace std::string_view_literals;
     17         constexpr std::string_view s_PreviewBuildSuffix = "-preview"sv;
     18 
     19         // Gets a boolean indicating whether the current process has identity.
     20         bool DoesCurrentProcessHaveIdentity()
     21         {
     22             UINT32 length = 0;
     23             LONG result = ::GetPackageFamilyName(GetCurrentProcess(), &length, nullptr);
     24             return (result != APPMODEL_ERROR_NO_PACKAGE);
     25         }
     26 
     27         std::unique_ptr<byte[]> GetPACKAGE_ID()
     28         {
     29             UINT32 bufferLength = 0;
     30             LONG gcpiResult = GetCurrentPackageId(&bufferLength, nullptr);
     31             THROW_HR_IF(E_UNEXPECTED, gcpiResult != ERROR_INSUFFICIENT_BUFFER);
     32 
     33             std::unique_ptr<byte[]> buffer = std::make_unique<byte[]>(bufferLength);
     34 
     35             gcpiResult = GetCurrentPackageId(&bufferLength, buffer.get());
     36             if (FAILED_WIN32_LOG(gcpiResult))
     37             {
     38                 return {};
     39             }
     40 
     41             return buffer;
     42         }
     43 
     44         // Gets the package name; only succeeds if running in a packaged context.
     45         std::string GetPackageName()
     46         {
     47             std::unique_ptr<byte[]> buffer = GetPACKAGE_ID();
     48             if (!buffer)
     49             {
     50                 return {};
     51             }
     52 
     53             PACKAGE_ID* packageId = reinterpret_cast<PACKAGE_ID*>(buffer.get());
     54             return Utility::ConvertToUTF8(packageId->name);
     55         }
     56 
     57         // Gets the package version; only succeeds if running in a packaged context.
     58         std::optional<PACKAGE_VERSION> GetPACKAGE_VERSION()
     59         {
     60             std::unique_ptr<byte[]> buffer = GetPACKAGE_ID();
     61             if (!buffer)
     62             {
     63                 return {};
     64             }
     65 
     66             PACKAGE_ID* packageId = reinterpret_cast<PACKAGE_ID*>(buffer.get());
     67             return packageId->version;
     68         }
     69     }
     70 
     71     bool IsRunningInPackagedContext()
     72     {
     73         static bool result = DoesCurrentProcessHaveIdentity();
     74         return result;
     75     }
     76 
     77     LocIndString GetClientVersion()
     78     {
     79         std::ostringstream strstr;
     80         strstr << VERSION_MAJOR << '.' << VERSION_MINOR << '.' << VERSION_BUILD;
     81 
     82         if (!IsReleaseBuild())
     83         {
     84             strstr << s_PreviewBuildSuffix;
     85         }
     86 
     87         return LocIndString{ strstr.str() };
     88     }
     89 
     90     std::wstring GetPackageFamilyName()
     91     {
     92         UINT32 length = 0;
     93         LONG returnValue = ::GetPackageFamilyName(GetCurrentProcess(), &length, nullptr);
     94 
     95         if (returnValue == APPMODEL_ERROR_NO_PACKAGE)
     96         {
     97             return {};
     98         }
     99 
    100         if (returnValue != ERROR_INSUFFICIENT_BUFFER)
    101         {
    102             THROW_IF_WIN32_ERROR(returnValue);
    103         }
    104 
    105         std::wstring result(length, '\0');
    106         returnValue = ::GetPackageFamilyName(GetCurrentProcess(), &length, &result[0]);
    107         THROW_IF_WIN32_ERROR(returnValue);
    108         THROW_HR_IF(E_UNEXPECTED, length == 0);
    109 
    110         result.resize(length - 1);
    111         return result;
    112     }
    113 
    114     LocIndString GetPackageVersion()
    115     {
    116         using namespace std::string_literals;
    117 
    118         if (IsRunningInPackagedContext())
    119         {
    120             auto version = GetPACKAGE_VERSION();
    121 
    122             if (!version)
    123             {
    124                 // In the extremely unlikely event of a failure, this is merely a sentinel value
    125                 // to indicated such.  The only other option is to completely prevent execution,
    126                 // which seems unnecessary.
    127                 return LocIndString{ "error"sv };
    128             }
    129 
    130             std::ostringstream strstr;
    131             strstr << GetPackageName() << " v" << version->Major << '.' << version->Minor << '.' << version->Build << '.' << version->Revision;
    132 
    133             return LocIndString{ strstr.str() };
    134         }
    135         else
    136         {
    137             // Calling code should avoid calling in when this is the case.
    138             return LocIndString{ "none"sv };
    139         }
    140     }
    141 
    142     LocIndString GetOSVersion()
    143     {
    144         winrt::Windows::System::Profile::AnalyticsInfo analyticsInfo{};
    145         auto versionInfo = analyticsInfo.VersionInfo();
    146 
    147         uint64_t version = std::stoull(Utility::ConvertToUTF8(versionInfo.DeviceFamilyVersion()));
    148         uint16_t parts[4];
    149 
    150         for (size_t i = 0; i < ARRAYSIZE(parts); ++i)
    151         {
    152             parts[i] = version & 0xFFFF;
    153             version = version >> 16;
    154         }
    155 
    156         std::ostringstream strstr;
    157         strstr << Utility::ConvertToUTF8(versionInfo.DeviceFamily()) << " v" << parts[3] << '.' << parts[2] << '.' << parts[1] << '.' << parts[0];
    158 
    159         return LocIndString{ strstr.str() };
    160     }
    161 
    162     std::string GetOSRegion()
    163     {
    164         winrt::Windows::Globalization::GeographicRegion region;
    165         return Utility::ConvertToUTF8(region.CodeTwoLetter());
    166     }
    167 
    168     bool IsCurrentOSVersionGreaterThanOrEqual(const Utility::Version& version)
    169     {
    170         DWORD versionParts[3] = {};
    171 
    172         for (size_t i = 0; i < ARRAYSIZE(versionParts) && i < version.GetParts().size(); ++i)
    173         {
    174             versionParts[i] = static_cast<DWORD>(std::min(static_cast<decltype(version.GetParts()[i].Integer)>(std::numeric_limits<DWORD>::max()), version.GetParts()[i].Integer));
    175         }
    176 
    177         OSVERSIONINFOEXW osVersionInfo{};
    178         osVersionInfo.dwOSVersionInfoSize = sizeof(osVersionInfo);
    179         osVersionInfo.dwMajorVersion = versionParts[0];
    180         osVersionInfo.dwMinorVersion = versionParts[1];
    181         osVersionInfo.dwBuildNumber = versionParts[2];
    182         osVersionInfo.wServicePackMajor = 0;
    183         osVersionInfo.wServicePackMinor = 0;
    184 
    185         DWORD mask = VER_MAJORVERSION | VER_MINORVERSION | VER_BUILDNUMBER | VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR;
    186 
    187         DWORDLONG conditions = 0;
    188         VER_SET_CONDITION(conditions, VER_MAJORVERSION, VER_GREATER_EQUAL);
    189         VER_SET_CONDITION(conditions, VER_MINORVERSION, VER_GREATER_EQUAL);
    190         VER_SET_CONDITION(conditions, VER_BUILDNUMBER, VER_GREATER_EQUAL);
    191         VER_SET_CONDITION(conditions, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);
    192         VER_SET_CONDITION(conditions, VER_SERVICEPACKMINOR, VER_GREATER_EQUAL);
    193 
    194         BOOL result = VerifyVersionInfoW(&osVersionInfo, mask, conditions);
    195         if (!result)
    196         {
    197             THROW_LAST_ERROR_IF(GetLastError() != ERROR_OLD_WIN_VERSION);
    198         }
    199         return !!result;
    200     }
    201 
    202     bool IsRunningAsAdmin()
    203     {
    204         return wil::test_token_membership(nullptr, SECURITY_NT_AUTHORITY, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS);
    205     }
    206 
    207     bool IsRunningAsSystem()
    208     {
    209         return wil::test_token_membership(nullptr, SECURITY_NT_AUTHORITY, SECURITY_LOCAL_SYSTEM_RID);
    210     }
    211 
    212     bool IsRunningAsAdminOrSystem()
    213     {
    214         return IsRunningAsAdmin() || IsRunningAsSystem();
    215     }
    216 
    217     bool IsRunningWithLimitedToken()
    218     {
    219         return wil::get_token_information<TOKEN_ELEVATION_TYPE>() == TokenElevationTypeLimited;
    220     }
    221 }