2012-03-02 7 views
6

Podpis dla głównej funkcji w C \ C++ mogą obejmować 3 argumenty:Uzyskaj wszystkie zmienne env w C C++ na Windows

main(int argc, char *argv[ ], char *envp[ ]) 

trzeci jest zmienne środowiskowe.

Kompiluję bibliotekę pod VS10 i dlatego nie mam main(). Jak mogę uzyskać zmienne środowiskowe dokładnie w tym samym typie, co w char *envp[]? Raczej nie używam .NET, aby zmniejszyć zależności i być może pewnego dnia będę otwarty na przenośność.

+0

getenv() i setenv() nie może być stosowany, ponieważ chcesz poznać całą listę ... ale jeśli używasz Visual Studio następnie rozwijać aplikację dla Windows, więc co z http://msdn.microsoft.com/en-us/library/ms683187%28v=vs.85%29.aspx? – Benoit

+0

Powiązane: http://stackoverflow.com/questions/2692855/extern-c-char-environ-windows-c-cli (być może nawet duplikat) – Flexo

+0

Sugeruję, że nie próbuj pisać wielojęzycznych plików źródłowych. – pmg

Odpowiedz

6

GetEnvironmentStrings zwraca wskaźnik (tylko do odczytu!) Na początek bloku środowiska dla procesu.

Blok jest ciągłym ciągiem w stylu C, który zawiera pary zakończone znakiem NUL key=value. Blok kończy się dodatkowym zakończeniem zerowym.

Aby uzyskać dostęp do bardziej wygodne, używać coś jak następujących funkcji:

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; 
} 

oczywiście właściwa realizacja będzie hermetyzacji to w klasie, a prawdopodobnie używać std::stringstream zamiast ręcznie iteracja ciągu znaków, łącząc ciągi na char na raz. Ale jestem leniwy.

Wykorzystanie jest tak:

environment_t env = get_env(); 

// Now you can write env[T("Var1")] to access a variable. 
+0

Czy mogę następnie rzucić 'char * []' na wartość zwracaną? Czy możesz dodać tę składnię, jeśli to możliwe, do swojej odpowiedzi? – Jonathan

+0

@ Jonathan Nie, nie możesz, 'LPTCH' jest typedef dla' TCHAR * '. Jest to ciąg pojedynczy * ciągły, a nie tablica ciągów.Ponieważ twoje pytanie jest otagowane, najprostszym sposobem na pracę z tym bałaganem jest sparsowanie go i umieszczenie go w wektorze. Poczekaj ... –

+0

Myślę, że powinna być pojedyncza "GetEnvironmentVariable": http://msdn.microsoft.com/en-us/library/windows/desktop/ms683188%28v=vs.85%29.aspx Jednak wymaga to wiedzy nazwa zmiennej z góry. –

4

nie wiem o oknach, ale na Linuksie to zmienna:

extern char **environ; 

jest dokładnie to, czego szukasz.

#include <stdio.h> 
#include <assert.h> 

extern char **environ; 

int main (int ac, char **av, char **envp) { 

    assert(envp == environ); 

} 
+3

'#include ' powinien zadeklarować 'environ' w dzisiejszych czasach. Był czas, gdy 'environ' była jedyną zmienną bez deklaracji nagłówka, ale w końcu to naprawili. –

+0

Biorąc pod uwagę odpowiedź na to pytanie (http://stackoverflow.com/questions/1370399/c-function-arg-char-is-not-the-same-as-char), myślę, że 'char ** environ' i 'char * envp []' są tego samego typu – Jonathan

1

Poniżej jest oparty o @Konrad's excellent answer z 2 głównych różnic:

  • Korzystanie wchar_t zamiast TCHAR. Nikt nie powinien używać nie szerokich znaków w systemie Windows.
  • Konstruowanie key i value przy użyciu std::wstring str(buffer, buflen), zgodnie z sugestią podaną w this answer. Uważam, że wydajność powinna być lepsza niż wykonanie char-by-char, chociaż nie zmierzyłem tego. Kod

:

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; 
}