The signature for the main function in C\C++ can include 3 arguments:
main( int argc, char *argv[ ], char *envp[ ] )
The third is the environment variables.
I'm compiling a library under VS10 and therefor I have no main()
. How can I get the environment variables in exactly the same type as is in char *envp[]
? I rather not use .NET as to decrease dependencies and perhaps one day be open to portability.
GetEnvironmentStrings
returns a (read-only!) pointer to the start of the environment block for a process.
The block is a contiguous C-style string that contains null-terminated key=value
pairs. The block is ended by an additional null termination.
To make access more convenient, use something like the following function:
typedef std::basic_string<TCHAR> tstring; // Generally convenient
typedef std::map<tstring, tstring> environment_t;
environment_t get_env() {
environment_t env;
auto free = [](LPTCH p) { FreeEnvironmentStrings(p); };
auto env_block = std::unique_ptr<TCHAR, decltype(free)>{
GetEnvironmentStrings(), free};
for (LPTCH i = env_block.get(); *i != T('\0'); ++i) {
tstring key;
tstring value;
for (; *i != T('='); ++i)
key += *i;
++i;
for (; *i != T('\0'); ++i)
value += *i;
env[key] = value;
}
return env;
}
Of course, a proper implementation would encapsulate this in a class, and probably use std::stringstream
rather than manually iterating over the characters, concatenating the strings on char
at a time. But I’m lazy.
Usage is like this:
environment_t env = get_env();
// Now you can write env[T("Var1")] to access a variable.
I don't know about windows, but on Linux this variable:
extern char **environ;
is exactly what you are looking for.
#include <stdio.h>
#include <assert.h>
extern char **environ;
int main (int ac, char **av, char **envp) {
assert(envp == environ);
}
The following is based of @Konrad's excellent answer, with 2 main differences:
wchar_t
rather than TCHAR
. No one should be using non-wide chars in Windows.key
and value
using std::wstring str(buffer, buflen)
, as suggested in this answer. I believe performance should be better than concating char-by-char, though I haven't measured it.code:
typedef std::map<std::wstring, std::wstring> environment_t;
environment_t get_env() {
environment_t env;
auto free = [](wchar_t* p) { FreeEnvironmentStrings(p); };
auto env_block = std::unique_ptr<wchar_t, decltype(free)>{
GetEnvironmentStringsW(), free};
for (const wchar_t* name = env_block.get(); *name != L'\0'; )
{
const wchar_t* equal = wcschr(name, L'=');
std::wstring key(name, equal - name);
const wchar_t* pValue = equal + 1;
std::wstring value(pValue);
env[key] = value;
name = pValue + value.length() + 1;
}
return env;
}
This is a variation of the existing answers in this question from Konrad and Jonathan that might help anyone wanting to create a single widechar string for logging to file or (in my case) for remote diagnostics. Feel free to upvote them instead.
LPWCH we = GetEnvironmentStrings();
const wchar_t* w = we;
do {
eline = w;
w += eline.length() + 1;
env += eline;
env += L"\r\n";
} while ((eline.length() > 0) && (*w != L'\0'));
FreeEnvironmentStrings(we);
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