Home > front end >  Append to registry without expanding variables
Append to registry without expanding variables

Time:04-29

I'll just start off by saying that I'm by no means an expert in C , so any pointers/tips are greatly appreciated. I'm having some difficulties reading and writing from registry, while keeping variables, i.e. not expanding them. I'm trying to append my executable path to the PATH environment variable (permanently), but I'm running into all sorts of problems. I have a long PATH variable that makes it impossible to edit without using a program or regedit, so I opted to create an "OldPath" variable with my current PATH variable, and change my PATH variable to %OldPath%. This has worked great, but now when I try to write to it with C , %OldPath% gets expanded into the old path variable and as a result, the variable gets truncated.

I tried first with normal strings, but I ended up with what looked like Chinese symbols in my PATH variable, so I changed it to wstring. Now I get normal strings, but the string gets truncated at 1172 characters.

My desired end result is that PATH is set to %OldPath;<current_path>

get_path_env()

inline std::wstring get_path_env()
{
    wchar_t* buf = nullptr;
    size_t sz = 0;
    if (_wdupenv_s(&buf, &sz, L"PATH") == 0 && buf != nullptr)
    {
        std::wstring path_env = buf;
        free(buf);
        return path_env;
    }
    return L"";
}

set_permanent_environment_variable()

inline bool set_permanent_environment_variable()
{
    const std::wstring path_env = get_path_env();
    if (path_env == L"")
    {
        return false;
    }
    std::wstringstream wss;
    wss << path_env;
    if (path_env.back() != ';')
    {
        wss << L';';
    }
    wss << std::filesystem::current_path().wstring() << L'\0';
    const std::wstring temp_data = wss.str();
    HKEY h_key;
    const auto key_path = TEXT(R"(System\CurrentControlSet\Control\Session Manager\Environment)");
    if (const auto l_open_status = RegOpenKeyExW(HKEY_LOCAL_MACHINE, key_path, 0, KEY_ALL_ACCESS, &h_key); l_open_status == ERROR_SUCCESS)
    {
        const auto data = temp_data.c_str();
        const DWORD data_size = static_cast<DWORD>(lstrlenW(data)   1);
        // ReSharper disable once CppCStyleCast
        const auto l_set_status = RegSetValueExW(h_key, L"PATH", 0, REG_EXPAND_SZ, (LPBYTE)data, data_size);
        RegCloseKey(h_key);
        if (l_set_status == ERROR_SUCCESS)
        {
            SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, reinterpret_cast<LPARAM>("Environment"), SMTO_BLOCK, 100, nullptr);
            return true;
        }
    }
    return false;
}

In other words, I want to find the equivalent of the following in C#:

var assemblyPath = Directory.GetParent(Assembly.GetEntryAssembly()!.Location).FullName;
var pathVariable = Environment.GetEnvironmentVariable("PATH", EnvironmentVariableTarget.Machine);
Environment.SetEnvironmentVariable("PATH", $"{pathVariable};{assemblyPath}", EnvironmentVariableTarget.Machine);

EDIT: I actually haven't tested if that code expands the value or not, but I want to do as the C# code states and if possible, not expand the variables in the path variable.

CodePudding user response:

You are trying to change the setting in the registry. So one would expect that you would get the value from the registry, change it, and set the value in the registry.

But you don't get the value from the registry. You get it from the environment? Why is that? The environment has the expanded version. It's like changing the wallpaper by taking a screenshot of the desktop, changing the screenshot, then setting it as the wallpaper, then asking how to remove the icons from the wallpaper.

The solution is to simply get the old value from the registry instead of the environment...

  • Related