Resources.cpp (6105B)
1 // Copyright (c) Microsoft Corporation. 2 // Licensed under the MIT License. 3 #include "pch.h" 4 #include "winget/Resources.h" 5 #include "Public/AppInstallerLogging.h" 6 #include "Public/AppInstallerStrings.h" 7 #include "Public/AppInstallerErrors.h" 8 9 namespace AppInstaller 10 { 11 namespace Resource 12 { 13 namespace 14 { 15 std::pair<void*, size_t> GetResourceData(PCWSTR resourceName, PCWSTR resourceType) 16 { 17 HMODULE resourceModule = nullptr; 18 GetModuleHandleExW( 19 GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, 20 reinterpret_cast<PCWSTR>(GetResourceData), 21 &resourceModule); 22 THROW_LAST_ERROR_IF_NULL(resourceModule); 23 24 HRSRC resourceInfoHandle = FindResourceW(resourceModule, resourceName, resourceType); 25 THROW_LAST_ERROR_IF_NULL(resourceInfoHandle); 26 27 HGLOBAL resourceMemoryHandle = LoadResource(resourceModule, resourceInfoHandle); 28 THROW_LAST_ERROR_IF_NULL(resourceMemoryHandle); 29 30 DWORD resourceSize = SizeofResource(resourceModule, resourceInfoHandle); 31 THROW_LAST_ERROR_IF(resourceSize == 0); 32 33 void* resourceContent = LockResource(resourceMemoryHandle); 34 THROW_HR_IF_NULL(E_UNEXPECTED, resourceContent); 35 36 return std::make_pair(resourceContent, static_cast<size_t>(resourceSize)); 37 } 38 } 39 40 std::string_view GetResourceAsString(int resourceName, int resourceType) 41 { 42 return GetResourceAsString(MAKEINTRESOURCE(resourceName), MAKEINTRESOURCE(resourceType)); 43 } 44 45 std::string_view GetResourceAsString(PCWSTR resourceName, PCWSTR resourceType) 46 { 47 auto resourceData = GetResourceData(resourceName, resourceType); 48 return { reinterpret_cast<char*>(resourceData.first), resourceData.second }; 49 } 50 51 std::pair<const BYTE*, size_t> GetResourceAsBytes(int resourceName, int resourceType) 52 { 53 return GetResourceAsBytes(MAKEINTRESOURCE(resourceName), MAKEINTRESOURCE(resourceType)); 54 } 55 56 std::pair<const BYTE*, size_t> GetResourceAsBytes(PCWSTR resourceName, PCWSTR resourceType) 57 { 58 auto resourceData = GetResourceData(resourceName, resourceType); 59 return std::make_pair(reinterpret_cast<BYTE*>(resourceData.first), resourceData.second); 60 } 61 62 // Utility class to load resources 63 struct Loader 64 { 65 // Gets the singleton instance of the resource loader. 66 static const Loader& Instance() 67 { 68 static Loader instance; 69 return instance; 70 } 71 72 // Gets the string resource value. 73 std::string ResolveString(std::wstring_view resKey) const 74 { 75 if (resKey.empty()) 76 { 77 return {}; 78 } 79 80 if (m_wingetLoader) 81 { 82 return Utility::ConvertToUTF8(m_wingetLoader.GetString(resKey)); 83 } 84 85 // Loader failed to load resource file, print the resource key instead. 86 return Utility::ConvertToUTF8(resKey); 87 } 88 89 // Gets the string resource value or nothing if not present. 90 std::optional<Resource::LocString> TryResolveString(std::wstring_view resKey) const 91 { 92 if (!resKey.empty() && m_wingetLoader) 93 { 94 try 95 { 96 winrt::hstring result = m_wingetLoader.GetString(resKey); 97 98 if (!result.empty()) 99 { 100 return Resource::LocString{ Utility::LocIndString{ Utility::ConvertToUTF8(result) } }; 101 } 102 } 103 CATCH_LOG() 104 } 105 106 return {}; 107 } 108 109 private: 110 winrt::Windows::ApplicationModel::Resources::ResourceLoader m_wingetLoader; 111 112 Loader() : m_wingetLoader(nullptr) 113 { 114 try 115 { 116 // The default constructor of ResourceLoader throws a winrt::hresult_error exception 117 // when resource.pri is not found. ResourceLoader::GetForViewIndependentUse also throws 118 // a winrt::hresult_error but for reasons unknown it only gets caught when running on the 119 // debugger. Running without a debugger will result in a crash that not even adding a 120 // catch all will fix. To provide a good error message we call the default constructor 121 // before calling GetForViewIndependentUse. 122 m_wingetLoader = winrt::Windows::ApplicationModel::Resources::ResourceLoader(); 123 m_wingetLoader = winrt::Windows::ApplicationModel::Resources::ResourceLoader::GetForViewIndependentUse(L"winget"); 124 } 125 catch (const winrt::hresult_error& hre) 126 { 127 // This message cannot be localized. 128 AICLI_LOG(CLI, Error, << "Failure loading resource file with error: " << hre.code()); 129 m_wingetLoader = nullptr; 130 } 131 } 132 }; 133 } 134 135 namespace StringResource 136 { 137 std::string StringId::Resolve() const 138 { 139 return Resource::Loader::Instance().ResolveString(*this); 140 } 141 142 std::ostream& operator<<(std::ostream& out, StringId si) 143 { 144 return (out << Resource::LocString{ si }); 145 } 146 147 std::optional<Resource::LocString> TryResolveString(std::wstring_view resKey) 148 { 149 return Resource::Loader::Instance().TryResolveString(resKey); 150 } 151 } 152 }