In an old Windows application I'm working on I need to get a path from an environment variable and then append onto it to build a path to a file. So the code looks something like this:
static std::string PathRoot; // Private variable stored in class' header file
char EnvVarValue[1024];
if (! GetEnvironmentVariable(L"ENV_ROOT", (LPWSTR) EnvVarValue, 1024))
{
cout << "Could not retrieve the ROOT env variable" << endl;
return;
}
else
{
PathRoot = EnvVarValue;
}
// Added just for testing purposes - Returning -1
int foundAt = PathRoot.find_first_of(':');
std::string FullFilePath = PathRoot;
FullFilePath.append("\\data\\Config.xml");
The environment value for ENV_ROOT is set to "c:\RootDir" in the Windows System Control Panel. But when I run the program I keep ending up with a string in FullFilePath that is missing the colon char and anything that followed in the root folder. It looks like this: "c\data\Config.xml".
Using the Visual Studio debugger I looked at EnvVarValue after passing the GetEnvironmentVariable line and it shows me an array that seems to have all the characters I'd expect, including the colon. But after it gets assigned to PathRoot, mousing over PathRoot only shows the C and drilling down it says something about a bad ptr. As I noted the find_first_of() call doesn't find the colon char. And when the append is done it only keeps the initial C and drops the rest of the RootDir value.
So there seems to be something about the colon character that is confusing the string constructor. Yes, there are a number of ways I could work around this by leaving the colon out of the env variable and adding it later in the code. But I'd prefer to find a way to have it read and used properly from the environment variable as it is.
You cannot simply cast a char*
to a wchar_t*
(by casting to LPWSTR
) and expect things to work. The two are fundamentally distinct types, and in Windows, they signify different encoding.
You obviously have WinAPI defines set such that GetEnvironmentVariable
resolves to GetEnvironmentVariableW
, which uses UTF-16 to encode the string. In practice, this means a 0
byte follows every ASCII character in memory.
You then construct a std::string
out of this, so it takes the first 0
byte (at char
index 1) as the string terminator, so you get just "c"
.
You have several options:
Use std::wstring
and wchar_t EnvVarValue[1024];
Call GetEnvironmentVariableA()
(which uses char
and ASCII)
Use wchar_t EnvVarValue[1024];
and convert the returned value to a std::string
using something like wcstombs
.
It seems you are building with wide-character functions (as indicated by your cast to LPWSTR
). This means that the string in EnvVarValue
is a wide-character string, and you you should be using wchar_t
and std::wstring
instead.
I would guess that the contents in the array array after the GetEnvironmentVariable
call is actually the ASCII values 0x43 0x00 0x3a 0x00 0x5c 0x00
etc. (that is the wide-char representation of "C:\"
). The first zero acts as the string terminator for a narrow-character string, which is why the narrow-character string PathRoot
only contains the 'C'
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With