附加到注册表而不扩展变量
Append to registry without expanding variables
首先我要说我绝不是 C++ 专家,所以非常感谢任何 pointers/tips。
我在从注册表读取和写入时遇到一些困难,同时保留变量,即不扩展它们。
我试图将我的可执行文件路径附加到 PATH 环境变量(永久),但我 运行 遇到了各种各样的问题。
我有一个很长的 PATH 变量,如果不使用程序或注册表编辑器就无法编辑,所以我选择用我当前的 PATH 变量创建一个“OldPath”变量,并将我的 PATH 变量更改为 %OldPath%。这工作得很好,但现在当我尝试用 C++ 写入它时,%OldPath% 被扩展到旧路径变量中,结果变量被截断。
我先尝试使用普通字符串,但最后我的 PATH 变量中出现了看起来像中文符号的内容,所以我将其更改为 wstring。现在我得到了正常的字符串,但字符串被截断为 1172 个字符。
我想要的最终结果是 PATH 设置为 %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'[=11=]';
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;
}
换句话说,我想在 C# 中找到以下等价物:
var assemblyPath = Directory.GetParent(Assembly.GetEntryAssembly()!.Location).FullName;
var pathVariable = Environment.GetEnvironmentVariable("PATH", EnvironmentVariableTarget.Machine);
Environment.SetEnvironmentVariable("PATH", $"{pathVariable};{assemblyPath}", EnvironmentVariableTarget.Machine);
编辑:我实际上还没有测试该代码是否扩展了值,但我想按照 C# 代码的说明进行操作,如果可能的话,不扩展路径变量中的变量。
您正在尝试更改注册表中的 PATH 设置。因此,人们会期望您从注册表中获取当前的 PATH 设置,更改它,然后在注册表中设置新的 PATH 设置。
但是您没有从注册表中获取 PATH 设置。您正在从环境中获取 PATH 变量。这是为什么?环境由注册表中的设置控制,但不是那个设置。特别是,您注意到在注册表中设置的环境变量在实际进入环境之前会得到扩展。
就像换壁纸一样,把桌面截图,换截图,然后设置为壁纸,然后问怎么去掉壁纸上的图标。
解决方案是简单地从注册表中获取当前未扩展的 PATH 设置,而不是从环境中获取扩展的设置。
首先我要说我绝不是 C++ 专家,所以非常感谢任何 pointers/tips。 我在从注册表读取和写入时遇到一些困难,同时保留变量,即不扩展它们。 我试图将我的可执行文件路径附加到 PATH 环境变量(永久),但我 运行 遇到了各种各样的问题。 我有一个很长的 PATH 变量,如果不使用程序或注册表编辑器就无法编辑,所以我选择用我当前的 PATH 变量创建一个“OldPath”变量,并将我的 PATH 变量更改为 %OldPath%。这工作得很好,但现在当我尝试用 C++ 写入它时,%OldPath% 被扩展到旧路径变量中,结果变量被截断。
我先尝试使用普通字符串,但最后我的 PATH 变量中出现了看起来像中文符号的内容,所以我将其更改为 wstring。现在我得到了正常的字符串,但字符串被截断为 1172 个字符。
我想要的最终结果是 PATH 设置为 %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'[=11=]';
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;
}
换句话说,我想在 C# 中找到以下等价物:
var assemblyPath = Directory.GetParent(Assembly.GetEntryAssembly()!.Location).FullName;
var pathVariable = Environment.GetEnvironmentVariable("PATH", EnvironmentVariableTarget.Machine);
Environment.SetEnvironmentVariable("PATH", $"{pathVariable};{assemblyPath}", EnvironmentVariableTarget.Machine);
编辑:我实际上还没有测试该代码是否扩展了值,但我想按照 C# 代码的说明进行操作,如果可能的话,不扩展路径变量中的变量。
您正在尝试更改注册表中的 PATH 设置。因此,人们会期望您从注册表中获取当前的 PATH 设置,更改它,然后在注册表中设置新的 PATH 设置。
但是您没有从注册表中获取 PATH 设置。您正在从环境中获取 PATH 变量。这是为什么?环境由注册表中的设置控制,但不是那个设置。特别是,您注意到在注册表中设置的环境变量在实际进入环境之前会得到扩展。
就像换壁纸一样,把桌面截图,换截图,然后设置为壁纸,然后问怎么去掉壁纸上的图标。
解决方案是简单地从注册表中获取当前未扩展的 PATH 设置,而不是从环境中获取扩展的设置。