【问题标题】:How can I overcome silent failure to change the PATH environment variable in VC++ 2013?如何克服在 VC++ 2013 中更改 PATH 环境变量的静默失败?
【发布时间】: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


【解决方案1】:

前提不正确。 PATHlast 搜索 DLL 的东西。

相反,您应该致电 SetDllDirectory()AddDllDirectory() 。这将设置 DLL 搜索路径,以便在可执行目录之后搜索您添加的路径

如果您需要比这更精细的控制,则需要指定 LoadLibrary() 函数的完整路径名。

【讨论】:

  • 嘿,Remy,我不介意编辑,但您将链接更改为指向 MS 网站的绝对链接,这些网站因移动东西而臭名昭著。我是否错误地使用了 make-google-find-it 链接?
  • 如果您使用完全限定路径,LoadLibraryExLOAD_WITH_ALTERED_SEARCH_PATH 标志是一种从目标 DLL 目录加载依赖项的方法,无需修改 PATH 或调用 @987654328 @。如果是 Windows 8+ 或更新的 Windows 7 系统,您还可以使用提供更多控制权的较新标志,例如 LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR,通过 SetDefaultDllDirectories 设置默认标志,并使用更灵活的 AddDllDirectory 功能添加目录。
  • @Dúthomhas,AddDllDirectory() 对我不起作用,但 LoadLibrary(pathname) 对我有用。谢谢!
猜你喜欢
  • 2021-05-06
  • 2015-01-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-19
  • 2018-03-20
  • 1970-01-01
  • 2016-01-06
相关资源
最近更新 更多