winget-cli

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

PathVariable.cpp (4643B)


      1 // Copyright (c) Microsoft Corporation.
      2 // Licensed under the MIT License.
      3 #include "pch.h"
      4 #include "winget/PathVariable.h"
      5 #include <winget/Filesystem.h>
      6 
      7 using namespace AppInstaller::Utility;
      8 
      9 namespace AppInstaller::Registry::Environment
     10 {
     11     namespace
     12     {
     13         constexpr std::wstring_view s_PathName = L"Path";
     14         constexpr std::wstring_view s_PathSubkey_User = L"Environment";
     15         constexpr std::wstring_view s_PathSubkey_Machine = L"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment";
     16 
     17         void EnsurePathValueEndsWithSemicolon(std::string& value)
     18         {
     19             if (value.back() != ';')
     20             {
     21                 value += ';';
     22             }
     23         }
     24 
     25         std::string ExpandPathValue(const std::string& value)
     26         {
     27             std::string result;
     28             std::vector<std::string> pathEntries = Split(value, ';');
     29             for (std::string& pathEntry : pathEntries)
     30             {
     31                 if (!pathEntry.empty())
     32                 {
     33                     result += AppInstaller::Filesystem::GetExpandedPath(pathEntry).u8string();
     34                     result += ';';
     35                 }
     36             }
     37             return result;
     38         }
     39     }
     40 
     41     PathVariable::PathVariable(Manifest::ScopeEnum scope, bool readOnly) : m_scope(scope), m_readOnly(readOnly)
     42     {
     43         if (m_readOnly)
     44         {
     45             if (m_scope == Manifest::ScopeEnum::Machine)
     46             {
     47                 m_key = Registry::Key::OpenIfExists(HKEY_LOCAL_MACHINE, std::wstring{ s_PathSubkey_Machine });
     48             }
     49             else
     50             {
     51                 m_key = Registry::Key::OpenIfExists(HKEY_CURRENT_USER, std::wstring{ s_PathSubkey_User });
     52             }
     53         }
     54         else
     55         {
     56             if (m_scope == Manifest::ScopeEnum::Machine)
     57             {
     58                 m_key = Registry::Key::Create(HKEY_LOCAL_MACHINE, std::wstring{ s_PathSubkey_Machine });
     59             }
     60             else
     61             {
     62                 m_key = Registry::Key::Create(HKEY_CURRENT_USER, std::wstring{ s_PathSubkey_User });
     63             }
     64         }
     65     }
     66 
     67     std::string PathVariable::GetPathValue()
     68     {
     69         std::wstring pathName = std::wstring{ s_PathName };
     70         return Normalize(m_key[pathName]->GetValue<Value::Type::String>());
     71     }
     72 
     73     bool PathVariable::Contains(const std::filesystem::path& target)
     74     {
     75         std::string targetString = Normalize(target.u8string());
     76         return (GetPathValue().find(targetString) != std::string::npos);
     77     }
     78 
     79     bool PathVariable::Remove(const std::filesystem::path& target)
     80     {
     81         THROW_HR_IF(E_ACCESSDENIED, m_readOnly);
     82 
     83         if (Contains(target))
     84         {
     85             std::string targetString = Normalize(target.u8string());
     86             std::string pathValue = GetPathValue();
     87             FindAndReplace(pathValue, targetString, "");
     88             FindAndReplace(pathValue, ";;", ";");
     89             SetPathValue(pathValue);
     90             return true;
     91         }
     92         else
     93         {
     94             return false;
     95         }
     96     }
     97 
     98     bool PathVariable::Append(const std::filesystem::path& target)
     99     {
    100         THROW_HR_IF(E_ACCESSDENIED, m_readOnly);
    101 
    102         if (!Contains(target))
    103         {
    104             std::string targetString = Normalize(target.u8string());
    105             std::string pathValue = GetPathValue();
    106             EnsurePathValueEndsWithSemicolon(pathValue);
    107             pathValue += targetString;
    108             EnsurePathValueEndsWithSemicolon(pathValue);
    109             SetPathValue(pathValue);
    110             return true;
    111         }
    112         else
    113         {
    114             return false;
    115         }
    116     }
    117 
    118     void PathVariable::SetPathValue(const std::string& value)
    119     {
    120         THROW_HR_IF(E_ACCESSDENIED, m_readOnly);
    121 
    122         std::wstring pathName = std::wstring{ s_PathName };
    123         m_key.SetValue(pathName, ConvertToUTF16(value), REG_EXPAND_SZ);
    124         SendNotifyMessageW(HWND_BROADCAST, WM_SETTINGCHANGE, 0, (LPARAM)TEXT("Environment"));
    125 
    126     }
    127 
    128     bool RefreshPathVariableForCurrentProcess()
    129     {
    130         // Path values must be expanded before assigning to process environment for proper refresh.
    131         std::string systemPathValue = ExpandPathValue(PathVariable(Manifest::ScopeEnum::Machine, true).GetPathValue());
    132         std::string userPathValue = ExpandPathValue(PathVariable(Manifest::ScopeEnum::User, true).GetPathValue());
    133         std::wstring pathValue = ConvertToUTF16(systemPathValue + userPathValue);
    134         return _wputenv_s(L"PATH", pathValue.c_str()) == 0;
    135     }
    136 }