Reputation: 2178
My goal is to write code that prepends a directory to the existing value of the PATH environment variable and sets the PATH environment variable to the new value for the duration of the program so that DLLs can be loaded from the new directory as well as from directories previously on the path. The code only needs to run on Windows and only needs to be compiled with Visual C++ 2013 and 2015. (Ideally, I'd like to be able to compile with MinGW as well, but the fact that there's no equivalent to /DELAYLOAD means that that may not be possible.)
I found, after experimentation, that SetEnvironmentVariable[W] silently fails to change the value of PATH, but _putenv, _putenv_s, _wputenv, and _wputenv_s work correctly --- but only on VC++ 2015. On VC++ 2013, they fail silently, and leave the value of PATH unchanged (the same way that SetEnvironmentVariable fails silently on VC++ 2013). I have not found any references to this behavior anywhere that I have searched on the Internet.
I can put up with using _putenv rather than SetEnvironmentVariable, but I need to figure out a way to change the value of PATH dynamically in VS2013, even if it's different from the way that works in VS2015.
UPDATE:
Here's prependDirToEnvVarW()
(and getPathFromEnvVarW()
, which it calls). prependDirToEnvVarW()
works correctly on VC++ 2015 but silently fails to change the path on 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;
}
}
Upvotes: 0
Views: 290
Reputation: 10083
The premise is incorrect. The PATH
is the last thing searched for DLLs.
Instead, you should be calling SetDllDirectory() or AddDllDirectory() . This sets the DLL search path so that your added path is searched second, right after the executable directory.
If you need finer control than that, you will need to specify a full pathname to the LoadLibrary()
function.
Upvotes: 3