winget-cli

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

Architecture.cpp (11377B)


      1 // Copyright (c) Microsoft Corporation.
      2 // Licensed under the MIT License.
      3 #include "pch.h"
      4 #include "Public/AppInstallerArchitecture.h"
      5 #include "Public/AppInstallerLogging.h"
      6 #include "Public/AppInstallerRuntime.h"
      7 #include "Public/AppInstallerStrings.h"
      8 
      9 namespace AppInstaller::Utility
     10 {
     11     using namespace literals;
     12     namespace
     13     {
     14         // IsWow64GuestMachineSupported() is available starting on Windows 10, version 1709 (RS3).
     15         // We generally target a later version (version 1809, RS5), but the WinGetUtil is used in
     16         // Azure Functions that run on version 1607 (RS1) where it is not available. So, we load and
     17         // call this function only if available.
     18         using IsWow64GuestMachineSupportedPtr = decltype(&IsWow64GuestMachineSupported);
     19 
     20         struct IsWow64GuestMachineSupportedHelper
     21         {
     22             IsWow64GuestMachineSupportedHelper()
     23             {
     24                 m_module.reset(LoadLibraryEx(L"api-ms-win-core-wow64-l1-1-2.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32));
     25                 if (!m_module)
     26                 {
     27                     AICLI_LOG(Core, Verbose, << "Could not load api-ms-win-core-wow64-l1-1-2.dll");
     28                     return;
     29                 }
     30 
     31                 m_isWow64GuestMachineSupported =
     32                     reinterpret_cast<IsWow64GuestMachineSupportedPtr>(GetProcAddress(m_module.get(), "IsWow64GuestMachineSupported"));
     33                 if (!m_isWow64GuestMachineSupported)
     34                 {
     35                     AICLI_LOG(Core, Verbose, << "Could not get proc address of IsWow64GuestMachineSupported");
     36                     return;
     37                 }
     38             }
     39 
     40             void AddArchitectureIfGuestMachineSupported(std::vector<Architecture>& target, Architecture architecture, USHORT guestMachine)
     41             {
     42                 if (m_isWow64GuestMachineSupported)
     43                 {
     44                     BOOL supported = FALSE;
     45                     LOG_IF_FAILED(m_isWow64GuestMachineSupported(guestMachine, &supported));
     46 
     47                     if (supported)
     48                     {
     49                         target.push_back(architecture);
     50                     }
     51                 }
     52             }
     53 
     54         private:
     55             wil::unique_hmodule m_module;
     56             IsWow64GuestMachineSupportedPtr m_isWow64GuestMachineSupported = nullptr;
     57         };
     58 
     59         void AddArchitectureIfGuestMachineSupported(std::vector<Architecture>& target, Architecture architecture, USHORT guestMachine)
     60         {
     61             IsWow64GuestMachineSupportedHelper helper;
     62             helper.AddArchitectureIfGuestMachineSupported(target, architecture, guestMachine);
     63         }
     64 
     65         // These types are defined in a future SDK and can be removed when we actually have them available.
     66         // The exception is that None was added (and this is an enum class).
     67         enum class MACHINE_ATTRIBUTES {
     68             None = 0,
     69             UserEnabled = 0x00000001,
     70             KernelEnabled = 0x00000002,
     71             Wow64Container = 0x00000004
     72         };
     73 
     74         DEFINE_ENUM_FLAG_OPERATORS(MACHINE_ATTRIBUTES);
     75 
     76         using GetMachineTypeAttributesPtr = HRESULT(WINAPI*)(USHORT Machine, MACHINE_ATTRIBUTES* MachineTypeAttributes);
     77 
     78         // GetMachineTypeAttributes can apparently replace IsWow64GuestMachineSupported, but no reason to do so right now.
     79         struct GetMachineTypeAttributesHelper
     80         {
     81             GetMachineTypeAttributesHelper()
     82             {
     83                 m_module.reset(LoadLibraryEx(L"api-ms-win-core-processthreads-l1-1-7.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32));
     84                 if (!m_module)
     85                 {
     86                     AICLI_LOG(Core, Verbose, << "Could not load api-ms-win-core-processthreads-l1-1-7.dll");
     87                     return;
     88                 }
     89 
     90                 m_getMachineTypeAttributes =
     91                     reinterpret_cast<GetMachineTypeAttributesPtr>(GetProcAddress(m_module.get(), "GetMachineTypeAttributes"));
     92                 if (!m_getMachineTypeAttributes)
     93                 {
     94                     AICLI_LOG(Core, Verbose, << "Could not get proc address of GetMachineTypeAttributes");
     95                     return;
     96                 }
     97             }
     98 
     99             void AddArchitectureIfMachineTypeAttributesUserEnabled(std::vector<Architecture>& target, Architecture architecture, USHORT guestMachine)
    100             {
    101                 if (m_getMachineTypeAttributes)
    102                 {
    103                     MACHINE_ATTRIBUTES attributes = MACHINE_ATTRIBUTES::None;
    104                     if (SUCCEEDED_LOG(m_getMachineTypeAttributes(guestMachine, &attributes)))
    105                     {
    106                         if (WI_IsFlagSet(attributes, MACHINE_ATTRIBUTES::UserEnabled))
    107                         {
    108                             target.push_back(architecture);
    109                         }
    110                     }
    111                 }
    112             }
    113 
    114         private:
    115             wil::unique_hmodule m_module;
    116             GetMachineTypeAttributesPtr m_getMachineTypeAttributes = nullptr;
    117         };
    118 
    119         void AddArchitectureIfMachineTypeAttributesUserEnabled(std::vector<Architecture>& target, Architecture architecture, USHORT guestMachine)
    120         {
    121             GetMachineTypeAttributesHelper helper;
    122             helper.AddArchitectureIfMachineTypeAttributesUserEnabled(target, architecture, guestMachine);
    123         }
    124 
    125         // Gets the applicable architectures for the current machine.
    126         std::vector<Architecture> CreateApplicableArchitecturesVector()
    127         {
    128             std::vector<Architecture> applicableArchs;
    129 
    130             switch (GetSystemArchitecture())
    131             {
    132             case Architecture::Arm64:
    133             {
    134                 applicableArchs.push_back(Architecture::Arm64);
    135                 AddArchitectureIfGuestMachineSupported(applicableArchs, Architecture::Arm, IMAGE_FILE_MACHINE_ARMNT);
    136                 AddArchitectureIfMachineTypeAttributesUserEnabled(applicableArchs, Architecture::X64, IMAGE_FILE_MACHINE_AMD64);
    137                 AddArchitectureIfGuestMachineSupported(applicableArchs, Architecture::X86, IMAGE_FILE_MACHINE_I386);
    138                 applicableArchs.push_back(Architecture::Neutral);
    139             }
    140                 break;
    141             case Architecture::Arm:
    142                 applicableArchs.push_back(Architecture::Arm);
    143                 applicableArchs.push_back(Architecture::Neutral);
    144                 break;
    145             case Architecture::X86:
    146                 applicableArchs.push_back(Architecture::X86);
    147                 applicableArchs.push_back(Architecture::Neutral);
    148                 break;
    149             case Architecture::X64:
    150                 applicableArchs.push_back(Architecture::X64);
    151                 AddArchitectureIfGuestMachineSupported(applicableArchs, Architecture::X86, IMAGE_FILE_MACHINE_I386);
    152                 applicableArchs.push_back(Architecture::Neutral);
    153                 break;
    154             default:
    155                 applicableArchs.push_back(Architecture::Neutral);
    156             }
    157 
    158             return applicableArchs;
    159         }
    160     }
    161 
    162     Architecture ConvertToArchitectureEnum(std::string_view archStr)
    163     {
    164         std::string arch = ToLower(archStr);
    165         if (arch == "x86")
    166         {
    167             return Architecture::X86;
    168         }
    169         else if (arch == "x64")
    170         {
    171             return Architecture::X64;
    172         }
    173         else if (arch == "arm")
    174         {
    175             return Architecture::Arm;
    176         }
    177         else if (arch == "arm64")
    178         {
    179             return Architecture::Arm64;
    180         }
    181         else if (arch == "neutral")
    182         {
    183             return Architecture::Neutral;
    184         }
    185 
    186         AICLI_LOG(Core, Info, << "ConvertToArchitectureEnum: Unknown architecture: " << archStr);
    187         return Architecture::Unknown;
    188     }
    189 
    190     std::optional<::AppInstaller::Utility::Architecture> ConvertToArchitectureEnum(winrt::Windows::System::ProcessorArchitecture architecture)
    191     {
    192         switch (architecture)
    193         {
    194         case winrt::Windows::System::ProcessorArchitecture::X86:
    195             return ::AppInstaller::Utility::Architecture::X86;
    196         case winrt::Windows::System::ProcessorArchitecture::Arm:
    197             return ::AppInstaller::Utility::Architecture::Arm;
    198         case winrt::Windows::System::ProcessorArchitecture::X64:
    199             return ::AppInstaller::Utility::Architecture::X64;
    200         case winrt::Windows::System::ProcessorArchitecture::Neutral:
    201             return ::AppInstaller::Utility::Architecture::Neutral;
    202         case winrt::Windows::System::ProcessorArchitecture::Arm64:
    203             return ::AppInstaller::Utility::Architecture::Arm64;
    204         }
    205 
    206         return {};
    207     }
    208 
    209     LocIndView ToString(Architecture architecture)
    210     {
    211         switch (architecture)
    212         {
    213         case Architecture::Neutral:
    214             return "Neutral"_liv;
    215         case Architecture::X86:
    216             return "X86"_liv;
    217         case Architecture::X64:
    218             return "X64"_liv;
    219         case Architecture::Arm:
    220             return "Arm"_liv;
    221         case Architecture::Arm64:
    222             return "Arm64"_liv;
    223         }
    224 
    225         return "Unknown"_liv;
    226     }
    227 
    228     Architecture GetSystemArchitecture()
    229     {
    230         Architecture systemArchitecture = Architecture::Unknown;
    231 
    232         USHORT processArchitecture = IMAGE_FILE_MACHINE_UNKNOWN;
    233         USHORT machineArchitecture = IMAGE_FILE_MACHINE_UNKNOWN;
    234         // Just log the error if failed and return architecture Unknown.
    235         LOG_IF_WIN32_BOOL_FALSE(IsWow64Process2(GetCurrentProcess(), &processArchitecture, &machineArchitecture));
    236 
    237         switch (machineArchitecture)
    238         {
    239         case IMAGE_FILE_MACHINE_AMD64:
    240             systemArchitecture = Architecture::X64;
    241             break;
    242         case IMAGE_FILE_MACHINE_ARM:
    243             systemArchitecture = Architecture::Arm;
    244             break;
    245         case IMAGE_FILE_MACHINE_ARM64:
    246             systemArchitecture = Architecture::Arm64;
    247             break;
    248         case IMAGE_FILE_MACHINE_I386:
    249             systemArchitecture = Architecture::X86;
    250             break;
    251         }
    252 
    253         return systemArchitecture;
    254     }
    255 
    256     const std::vector<Architecture>& GetApplicableArchitectures()
    257     {
    258         static std::vector<Architecture> applicableArchs = CreateApplicableArchitecturesVector();
    259         return applicableArchs;
    260     }
    261 
    262     const std::vector<Architecture>& GetAllArchitectures()
    263     {
    264         static std::vector<Architecture> allArchs = { Architecture::Neutral, Architecture::X86, Architecture::X64, Architecture::Arm, Architecture::Arm64 };
    265         return allArchs;
    266     }
    267 
    268     int IsApplicableArchitecture(Architecture arch)
    269     {
    270         return IsApplicableArchitecture(arch, GetApplicableArchitectures());
    271     }
    272 
    273     int IsApplicableArchitecture(Architecture arch, const std::vector<Architecture>& allowedArchitectures)
    274     {
    275         auto it = std::find(allowedArchitectures.begin(), allowedArchitectures.end(), arch);
    276 
    277         if (it != allowedArchitectures.end())
    278         {
    279             return static_cast<int>(std::distance(it, allowedArchitectures.end()));
    280         }
    281         else
    282         {
    283             return InapplicableArchitecture;
    284         }
    285     }
    286 }