【发布时间】:2018-03-14 04:37:06
【问题描述】:
我的目标是编写代码,将目录添加到 PATH 环境变量的现有值,并在程序运行期间将 PATH 环境变量设置为新值,以便也可以从新目录加载 DLL与路径上先前的目录一样。该代码只需要在 Windows 上运行,并且只需要使用 Visual C++ 2013 和 2015 进行编译。(理想情况下,我也希望能够使用 MinGW 进行编译,但没有等效于 /DELAYLOAD 的事实意味着这可能是不可能的。)
经过实验,我发现 SetEnvironmentVariable[W] 静默无法更改 PATH 的值,但 _putenv、_putenv_s、_wputenv 和 _wputenv_s 可以正常工作 --- 但仅在 VC++ 2015 上。在 VC++ 2013 上,它们静默失败,并保持 PATH 的值不变(与 SetEnvironmentVariable 在 VC++ 2013 上静默失败的方式相同)。我在 Internet 上搜索过的任何地方都没有找到任何关于此行为的参考。
我可以忍受使用 _putenv 而不是 SetEnvironmentVariable,但我需要想办法在 VS2013 中动态更改 PATH 的值,即使它与 VS2015 中的工作方式不同。
更新:
这里是 prependDirToEnvVarW()(和它所调用的 getPathFromEnvVarW())。 prependDirToEnvVarW() 在 VC++ 2015 上可以正常工作,但在 VC++ 2013 上无法更改路径。
inline std::wstring getPathFromEnvVarW()
{
DWORD bufferSize = GetEnvironmentVariableW(L"PATH", NULL, 0);
std::wstring ret(bufferSize, wchar_t(0));
DWORD getPathEnv = GetEnvironmentVariableW(L"PATH", &ret[0], bufferSize);
return (getPathEnv ? ret : L"");
}
inline bool prependDirToEnvVarW(const std::wstring & wstrDir)
{
const std::wstring PATH_VAR_NAME = L"PATH";
std::wstring wstrPrevPath = getPathFromEnvVarW();
std::wstring wstrValue = wstrDir;
if (!wstrValue.empty() && wstrValue[wstrValue.length() - 1] != L';')
{
wstrValue += L";";
}
wstrValue += wstrPrevPath;
std::replace(wstrValue.begin(), wstrValue.end(), L'/', L'\\');
errno_t retVal = _wputenv_s(PATH_VAR_NAME.c_str(), wstrValue.c_str());
std::cout << "Attempted to change PATH to:\n" <<
std::string(wstrValue.cbegin(), wstrValue.cend()) << std::endl;
if (retVal == 0)
{
return true;
}
else
{
std::cout << "retVal is nonzero: " << retVal
<< " (compare to EINVAL == " << EINVAL << ")" << std::endl;
return false;
}
}
【问题讨论】:
-
SetEnvironmentVariable 应该可以工作。您可能需要发布minimal reproducible example。另一方面,DLL 通常应该使用显式路径加载,这样可以完全避免这个问题。
-
请注意,
_putenv仅影响 C 环境而不影响 Windows 环境是(或曾经是 IIRC)正常的。因此,目前发布的代码可能会失败。但是我不清楚您对 PATH 所做的究竟是什么,这使您得出结论认为它没有被更改;你也可以发布那部分代码吗?
标签: c++ windows environment-variables