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 }