Reputation: 8576
I am working on a C++ Console Application in Visual Studio 2012 on Windows 7 and I want to get the values of some environment variables from within the application.
Here is what I've tried so far -:
int main()
{
char a[1000];
int s=GetEnvironmentVariableA("HOME",a,1000);
}
However, I am getting the value of s
to be 0, indicating that variable "HOME" does not exist.
Also, getenv("HOME")
returns NULL
too.
So, what is the correct procedure of doing this ?
Upvotes: 4
Views: 3882
Reputation: 612894
What this program is telling you, most likely, is that your process environment does not contain a variable named HOME
. Note that HOME
is not a variable that you would expect to be defined, unless you have taken steps to define it. Either by adding it to the system's environment, or by specifying a bespoke environment when creating the process.
The documentation says the following about the return value:
If the function succeeds, the return value is the number of characters stored in the buffer pointed to by lpBuffer, not including the terminating null character.
If lpBuffer is not large enough to hold the data, the return value is the buffer size, in characters, required to hold the string and its terminating null character and the contents of lpBuffer are undefined.
If the function fails, the return value is zero. If the specified environment variable was not found in the environment block, GetLastError returns ERROR_ENVVAR_NOT_FOUND.
So, if the function returns 0
, do as the documentation says. Call GetLastError
to find out why the function call failed.
But as I said, with probability very close to 1, the reason will simply be that your process environment has not defined a variable named HOME
.
As to how you move forward, most likely you are looking for a location in the user's profile. Exactly how you do this will depend on where in the profile you wish to store/load the file. One of the APIs related to CSIDL or known folder IDs will serve your needs.
Upvotes: 4
Reputation: 145239
Regarding your question,
” So, what is the correct procedure of doing this ?
Windows doesn't have a single HOME
standard variable. Instead, in the old days there were HOMEDRIVE
and HOMEPATH
, and apparently because they didn't know about it, with Windows Explorer in Windows 95, a new variable called USERPROFILE
.
[C:\Users\alfps_000] > set home HOMEDRIVE=C: HOMEPATH=\Users\alfps_000 [C:\Users\alfps_000] > set user USERDOMAIN=FRIKADELL USERDOMAIN_ROAMINGPROFILE=FRIKADELL USERNAME=alfps_000 USERPROFILE=C:\Users\alfps_000 [C:\Users\alfps_000] > _
The silly triple-oh suffix (as if I were better than double-oh seven) is just what Windows 8.1 saw fit to give me. It's just too much work to cajole Windows into reasonable choices. And so not just with usernames but also with environment variables.
Here's your program rewritten to use the Windows variable that vaguely corresponds to Unix-land HOME
, namely USERPROFILE
:
#include <iostream>
#include <stdlib.h> // getenv
using namespace std;
auto main() -> int
{
cout
<< "User's profile directory: "
<< "[" << getenv( "USERPROFILE" ) << "]"
<< endl;
}
The Windows environment variables are awkward and not guaranteed, but still usable in scripts and very simple programs like the one above. In more serious C++ code you can instead use the SHGetKnownFolderPath
API function. With Visual C++ it can look like this:
#undef UNICODE
#define UNICODE
#include <windows.h>
#include <shlobj.h> // SHGetKnownFolderPath
#include <objbase.h> // CoTaskMemFree
#include <iostream> // std::wcout
#include <memory> // std::unique_ptr
#include <stdexcept> // std::runtime_error, std::exception
#include <stdlib.h> // EXIT_FALURE, EXIT_SUCCESS
using namespace std;
void cotaskmem_free( wchar_t* p ) { CoTaskMemFree( p ); }
auto main() -> int
{
using X = runtime_error;
using String_deallocation = unique_ptr<wchar_t[], void(*)(wchar_t*)>;
try
{
wchar_t* path;
HRESULT const hr = SHGetKnownFolderPath(
FOLDERID_Profile, // REFKNOWNFOLDERID rfid -> %USERPROFILE%
0, // DWORD dwFlags,
0, // HANDLE hToken,
&path // PWSTR *ppszPath
);
if( FAILED( hr ) ) { throw X( "SHGetKnownFolderPath failed" ); }
String_deallocation const path_cleanup( path, cotaskmem_free );
wcout << "User profile directory: [" << path << "]" << endl;
return EXIT_SUCCESS;
}
catch( exception const& x )
{
wcerr << "!" << x.what() << endl;
}
return EXIT_FAILURE;
}
g++ (per version 4.8.2) doesn't yet support API functions from Windows Vista and onward, at least not in general, so if you need to support g++ use some older function.
Note:
It's not unlikely that whatever you intended to access or place in %HOME%
, would better be accessed or placed in one of the other special users's directories, also available via SHGetKnownFolderPath
.
Upvotes: 4