2012-03-02 10 views
6

上のC \ C++のすべてのENV変数を取得しますC \ C++のmain関数のシグネチャは、3つの引数を含めることができます。Windowsの

私はVS10でライブラリをコンパイルしているので、私にはmain()がありません。 char *envp[]とまったく同じタイプの環境変数を取得するにはどうすればよいですか?依存性を減らすために.NETを使用するのではなく、たぶん一日で移植性が向上します。

+0

のgetenv()とのsetenv()を使用することはできません...しかし、Visual Studioを使用している場合、あなたは、Windows用のアプリケーションを開発しますだから約http://msdn.microsoft.com/en-us/library/ms683187%28v=vs.85%29.aspx? – Benoit

+0

関連:http://stackoverflow.com/questions/2692855/extern-c-char-environ-windows-c-cli(恐らく詐欺師) – Flexo

+0

多言語のソースファイルを書くことはお勧めしません。 – pmg

答えて

6

GetEnvironmentStringsは、プロセスの環境ブロックの先頭に(読み取り専用!)ポインタを返します。

このブロックは、Nullで終端されたkey=valueのペアを含む連続したCスタイルの文字列です。ブロックは、追加のヌル終了によって終了します。

次の関数のようなものを使用、アクセスがより便利にするために:もちろん

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

を、適切な実装では、クラスでこれをカプセル化し、そしておそらく文字を反復手動std::stringstreamではなくを使用し、連結します一度にcharにある文字列。しかし、私は怠け者です。

使用法は、このようなものです:

environment_t env = get_env(); 

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

戻り値に 'char * []'をキャストできますか?可能であれば、この構文をあなたの答えに追加できますか? – Jonathan

+0

@Jonathanいいえ、「LPTCH」は 'TCHAR * 'のtypedefです。これは文字列の配列ではなく、*単一の連続した文字列です。あなたの質問はタグ付けされているので、この混乱を処理する最も簡単な方法は、解析してベクトルに入れることです。待つ... –

+0

私はそれが単なる "GetEnvironmentVariable"であるべきだと思います:http://msdn.microsoft.com/en-us/library/windows/desktop/ms683188%28v=vs.85%29.aspx しかしこれには知る必要があります変数の名前を事前に指定します。 –

4

私は窓のことは知らないが、Linux上でこの変数:

extern char **environ; 

は、あなたが探しているまさにです。

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

extern char **environ; 

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

    assert(envp == environ); 

} 
+3

'#include 'は最近、 'environ'を宣言するべきです。 'environ'が宣言するヘッダーのない唯一の変数だった時がありましたが、最終的にそれを修正しました。 –

+0

[この質問](http://stackoverflow.com/questions/1370399/c-function-arg-char-is-not-the-same-as-char)への答えを考えると、 'char ** environ'と 'char * envp []'は同じ型です – Jonathan

1

以下は2つの主要な違いと、@Konrad's excellent answerの基づいている:wchar_tなくTCHARを使用

  • 。誰もWindowsで非ワイド文字を使用するべきではありません。
  • this answerで示唆されるように、std::wstring str(buffer, buflen)を使用してkeyおよびvalueを構成する。私はそれを測定していませんが、パフォーマンスはchar-by-charを連結するよりも良いはずです。

コード:、あなたが全体のリストを知りたいので、

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