Z.K.e.2016
Z.K.e.2016

Reputation: 11

is there better way for making path through Environment variables in c/c++?

is there better way for making path through Environment variables in c/c++ than this?

char *S1 = std::getenv("SystemDrive");
char *S2 = std::getenv("USERNAME");
strcat(S1,"\\\\Users\\\\");
strcat(S1,S2);
strcat(S1,"\\\\");
strcat(S1,"Documents");

Upvotes: 0

Views: 524

Answers (5)

bodangly
bodangly

Reputation: 2624

I would recommend getting the user profile directory something like this.

BOOL GetCurrentUserDir(LPTSTR lpszBuf, LPDWORD lpdwBuflen)
{
    HANDLE hProcessToken;

    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &hProcessToken))
        return FALSE;

    if (!GetUserProfileDirectory(hProcessToken, lpszBuf, lpdwBuflen)) {
        CloseHandle(hProcessToken);
        return FALSE;
    }

    CloseHandle(hProcessToken);
    return TRUE;
}

I used this function like so:

WCHAR szLocalPath[MAX_PATH];
if (!GetCurrentUserDir(szLocalPath, &cchPath))
{
    //Handle the error
}

You can then append the rest of the path.

This encapsulates the specific environment variables and makes use of the Win32 API. This is more likely to remain portable over time.

Upvotes: 2

shrike
shrike

Reputation: 4511

Not sure to understand what you need exactly. Is this to create paths from environment variables ? or to get proper paths of system directory ? in the latter case, you would better use the Win32 API, e.g.: SHGetFolderPath or SHGetKnownFolderPath.

#include <Windows.h>
#include <ShellAPI.h>
#include <KnownFolders.h>
#include <ShlObj.h>

int main()
{
    CoInitialize(NULL);
    TCHAR* path = 0;
    SHGetKnownFolderPath(FOLDERID_Documents, KF_FLAG_SIMPLE_IDLIST, NULL, &path);
    // use collected 'path' here
    CoTaskMemFree(path);    // free the TCHAR object allocated by SHGetKnownFolderPath
    return 0;
}

The above code retrieve the current user "My Documents" folder path.

Upvotes: 0

Smash
Smash

Reputation: 3802

std::getenv is deprecated.

I would use something in the likes:

char*  wSystemDrive = nullptr;
size_t wSize = 0;

bool wFree = true;

if(_dupenv_s(&wSystemDrive,&wSize,"SystemDrive") != 0 || wSystemDrive == nullptr)
{
    wFree = false;

    wSystemDrive = "C:\\"; //or anything default you want to use
}

std::string wSysteDriveString(wSystemDrive);

if(wFree)
{
    free(wSystemDrive);
}

char*  wUSERNAME = nullptr;
wSize = 0;

wFree = true;

if(_dupenv_s(&wEnv,&wSize,"wUSERNAME") != 0 || wUSERNAME == nullptr)
{
    wFree = false;

    wUSERNAME = "User";
}

std::string wUSERNAMEString(wUSERNAME);

if(wFree)
{
    free(wUSERNAME);
}

std::string wPath = wSystemDriveString + "\\Users\\" + wUSERNAMEString + "\\Documents"

Note that you do not need 4 \ (\\\\), only two (\\).

Upvotes: -1

Maxim Egorushkin
Maxim Egorushkin

Reputation: 136296

One good way to concatenate multiple strings is to use snprintf:

char buf[0x10000];
int n = std::snprintf(buf, sizeof buf, "%s\\\\Users\\\\%s\\\\Documents", S1, S2);
if(static_cast<size_t>(n) >= sizeof buf)
    // Buffer is too small (if n > 0) or error

The fact that snprintf does not overflow the buffer and always zero-terminates makes unsafe functions strcpy, strncpy, strcat unnecessary.

Upvotes: 1

Ethan F.
Ethan F.

Reputation: 251

Why don't you use std::string?

std::string s1 = std::getenv("SystemDrive");
s1 += "\\\\Users\\\\" + std::getenv("USERNAME") + "\\\\Documents";

Upvotes: 1

Related Questions