2012-03-02 12 views
6

La firma para la función principal en C \ C++ puede incluir 3 argumentos:Obtener todas las variables env en C C++ en Windows

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

La tercera es la variable de entorno.

Estoy compilando una biblioteca en VS10 y por lo tanto no tengo main(). ¿Cómo puedo obtener las variables de entorno exactamente del mismo tipo que en char *envp[]? Prefiero no utilizar .NET para disminuir las dependencias y quizás algún día estar abierto a la portabilidad.

+0

getenv() y setenv() no se pueden utilizar porque quiere conocer la lista entera ... pero si usted está utilizando Visual Studio entonces desarrollar aplicaciones para Windows, Entonces, ¿qué pasa con http://msdn.microsoft.com/en-us/library/ms683187%28v=vs.85%29.aspx? – Benoit

+0

Relacionados: http://stackoverflow.com/questions/2692855/extern-c-char-environ-windows-c-cli (posiblemente incluso un dupe) – Flexo

+0

Sugiero que no intente escribir archivos fuente en varios idiomas. – pmg

Respuesta

6

GetEnvironmentStrings devuelve un puntero (de solo lectura) al inicio del bloque de entorno para un proceso.

El bloque es una cadena de estilo C contigua que contiene key=value pares terminados en nulo. El bloque termina con una terminación nula adicional.

para hacer el acceso más conveniente, utilizar algo como la siguiente función:

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

Por supuesto, una aplicación adecuada sería encapsular esto en una clase, y probablemente utilice std::stringstream en lugar de iterar manualmente a través de los personajes, la concatenación las cadenas en char a la vez. Pero soy flojo.

El uso es la siguiente:

environment_t env = get_env(); 

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

¿Puedo entonces lanzar 'char * []' en el valor de retorno? ¿Podría agregar esta sintaxis si es posible a su respuesta? – Jonathan

+0

@Jonathan No, no puedes, 'LPTCH' es un typedef para' TCHAR * '. Es una cadena contigua * única *, no una matriz de cadenas.Dado que se etiqueta a su pregunta, la forma más fácil de trabajar con este lío es analizarlo y ponerlo en un vector. Espera ... –

+0

Creo que debería ser singular "GetEnvironmentVariable": http://msdn.microsoft.com/en-us/library/windows/desktop/ms683188%28v=vs.85%29.aspx Sin embargo, esto requiere saber el nombre de la variable por adelantado. –

4

No sé acerca de las ventanas, pero en Linux esta variable:

extern char **environ; 

es exactamente lo que busca.

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

extern char **environ; 

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

    assert(envp == environ); 

} 
+3

'' # include debe declarar 'environ' estos días. Hubo un tiempo en que 'environ' fue la única variable sin un encabezado de declarar, pero que finalmente se solucionó. –

+0

dado la respuesta a [esta cuestión] (http://stackoverflow.com/questions/1370399/c-function-arg-char-is-not-the-same-as-char), supongo que 'char ** environ' y 'char * envp []' son del mismo tipo – Jonathan

1

Lo siguiente se basa de @Konrad's excellent answer, con 2 diferencias principales:

  • Usando wchar_t en lugar de TCHAR. Nadie debería usar caracteres no anchos en Windows.
  • Construyendo key y value usando std::wstring str(buffer, buflen), como se sugiere en this answer. Creo que el rendimiento debería ser mejor que la concatenación char-by-char, aunque no lo he medido.

código:

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