winget-cli

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

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 }