如何尽可能干净地使用 VS C GetEnvironmentVariable?

新手上路,请多包涵

(这与其说是学究气的练习,不如说是一个问题,所以就这样吧。)

我已经制作了一个不错的小程序,它是我的 linux 操作系统的原生程序,但我认为它也足以存在于我的 Windows 机器上。因此,我想访问 Windows 的环境变量,MSDN 引用了一个这样的例子:

 const DWORD buff_size = 50;
LPTSTR buff = new TCHAR[buff_size];

const DWORD var_size = GetEnvironmentVariable("HOME",buff,buff_size);

if (var_size==0) { /* fine, some failure or no HOME */ }
else if (var_size>buff_size) {

    // OK, so 50 isn't big enough.
    if (buff) delete [] buff;
    buff = new TCHAR[var_size];

    const DWORD new_size = GetEnvironmentVariable("HOME",buff,var_size);

    if (new_size==0 || new_size>var_size) { /* *Sigh* */ }
    else { /* great, we're done */ }
}
else { /* in one go! */ }

这不像使用 getenv 并仅检查空指针那么好(对我来说)。我也不想动态分配内存,因为我只是想让程序在 Windows 和我的 linux 操作系统上运行,这意味着这个 MS 代码必须与 nix 代码很好地配合。进一步来说:

 template <class T> // let the compiler sort out between char* and TCHAR*
inline bool get_home(T& val) { // return true if OK, false otherwise
#if defined (__linux) || (__unix)
    val = getenv("HOME");
    if (val) return true;
    else return false;
#elif defined (WINDOWS) || defined (_WIN32) || defined (WIN32)
    // something like the MS Code above
#else
    // probably I'll just return false here.
#endif
}

因此,我必须在堆上进行普遍分配,或者在调用函数中执行 #ifdef 以释放内存。不是很漂亮。

当然,我可以首先在堆栈上分配“buff”,但是如果在第一次调用 GetEnvironmentVariable 时“buff_size”不够大,我必须创建一个新的 TCHAR[] .更好,但是如果我是一个书呆子并且不想到处创建多余的数组怎么办?关于更美观的东西的任何想法?

我不是那么知识渊博,所以有人会嫉妒我故意强迫 GetEnvironmentVariable 失败以获得字符串大小吗?有没有人看到以下问题:

 const DWORD buff_size = GetEnvironmentVariable("HOME",0,0);
TCHAR buff[buff_size];
const DWORD ret = GetEnvironmentVariable("HOME",buff,buff_size);
// ...

还有其他想法或建议吗? (或者纠正明显的错误?)

更新:下面有很多有用的信息。我认为我想做的最好的选择是使用 static char[] 比如:

 inline const char* get_home(void) { // inline not required, but what the hell.
#if defined (__linux) || (__unix)
    return getenv("HOME");
#elif defined (WINDOWS) || defined (WIN32) || defined (_WIN32)
    static char buff[MAX_PATH];
    const DWORD ret = GetEnvironmentVariableA("USERPROFILE",buff,MAX_PATH);
    if (ret==0 || ret>MAX_PATH)
        return 0;
    else
        return buff;
 #else
        return 0;
 #endif
 }

也许这不是最优雅的方式,但它可能是在 *nix 和 Windows 之间同步我想做的最简单的方式。 (稍后我还会担心 Unicode 支持。)

感谢所有帮助过的人。

原文由 Zorawar 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 829
2 个回答
DWORD bufferSize = 65535; //Limit according to http://msdn.microsoft.com/en-us/library/ms683188.aspx
std::wstring buff;
buff.resize(bufferSize);
bufferSize = GetEnvironmentVariableW(L"Name", &buff[0], bufferSize);
if (!bufferSize)
    //error
buff.resize(bufferSize);

当然,如果您想要 ASCII,请将 wstring 替换为 stringGetEnvironmentVariableW 替换为 —c31fe GetEnvironmentVariableA

编辑:您也可以自己创建 getenv 。这有效,因为

后续调用 getenv 时可能会使用相同的内存位置,从而覆盖之前的内容。

 const char * WinGetEnv(const char * name)
{
    const DWORD buffSize = 65535;
    static char buffer[buffSize];
    if (GetEnvironmentVariableA(name, buffer, buffSize))
    {
        return buffer;
    }
    else
    {
        return 0;
    }
}

当然,如果您想保持对 unicode 的支持,那么使用所有这些的宽字符版本可能是一个好主意。

原文由 Billy ONeal 发布,翻译遵循 CC BY-SA 2.5 许可协议

这不是最初的问题,但可能值得将 MFC 方式添加到此线程以供参考:

 CString strComSpec;
if (strComSpec.GetEnvironmentVariable(_T("COMSPEC")))
{
    //Do your stuff here
}

原文由 user1228651 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题