如何使用VS C + + GetEnvironmentVariable尽可能干净? [英] How to use VS C++ GetEnvironmentVariable as cleanly as possible?

查看:452
本文介绍了如何使用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){/ *很好,一些失败或没有HOME * /}
else if(var_size> buff_size){

OK,所以50不够大。
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 done done * /}
}
else {/ *一次性! * /}

这不像使用getenv那么好空指针。我也不喜欢动态分配内存,因为我只是想让程序运行在Windows以及我的linux操作系统,这意味着这个MS代码必须运行良好的nix代码。更具体地:

 模板< class T> //让编译器在char *和TCHAR之间进行整理* 
inline bool get_home(T& val){//如果正确返回true,否则返回false
#if defined(__linux)|| (__unix)
val = getenv(HOME);
if(val)return true;
else return false;
#elif defined(WINDOWS)|| defined(_WIN32)|| (WIN32)
//像上面的MS代码
#else
//可能我在这里返回false。
#endif
}

堆通用或在调用函数中执行 #ifdef 以释放内存。不是很漂亮。



当然,我可以刚刚在堆栈上分配buff,但是我必须创建一个新的 TCHAR [] 如果'buff_size'在我第一次调用GetEnvironmentVariable时不足够大。更好,但如果我是一个踏脚石,不想去创造多余的数组呢?对于更美观的东西的任何想法?



我不知道,所以任何人都会吝惜我故意强迫GetEnvironmentVariable失败,以获得一个字符串大小?任何人都看到一个问题:

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

任何其他想法或建议? (或更正显着的错误?)



更新:
下面有很多有用的信息。我认为最好的打赌,我想做的是使用 static char [] like:

  inline const char * get_home(void){// inline不是必需的,但是到底是什么。 
#if defined(__linux)|| (__unix)
return getenv(HOME);
#elif defined(WINDOWS)||定义(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支持。)



感谢您的帮助。

解决方案

  DWORD bufferSize = 65535; //限制根据http://msdn.microsoft.com/en-us/library/ms683188.aspx 
std :: wstring buff;
buff.resize(bufferSize);
bufferSize = GetEnvironmentVariableW(LName,& buff [0],bufferSize);
if(!bufferSize)
//错误
buff.resize(bufferSize);

当然,如果你想要ASCII,替换 wstring with string GetEnvironmentVariableW p>

编辑:您也可以创建 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支持。


(This is not so much a problem as an exercise in pedantry, so here goes.)

I've made a nice little program that is native to my linux OS, but I'm thinking it's useful enough to exist on my Windows machine too. Thus, I'd like to access Windows' environment variables, and MSDN cites an example like this:

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! */ }

This is not nearly as nice (to me) as using getenv and just checking for a null pointer. I'd also prefer not to dynamically allocate memory since I'm just trying to make the program run on Windows as well as on my linux OS, which means that this MS code has to play nicely with nix code. More specifically:

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
}

So, I'd have to allocate on the heap universally or do a #ifdef in the calling functions to free the memory. Not very pretty.

Of course, I could have just allocated 'buff' on the stack in the first place, but then I'd have to create a new TCHAR[] if 'buff_size' was not large enough on my first call to GetEnvironmentVariable. Better, but what if I was a pedant and didn't want to go around creating superfluous arrays? Any ideas on something more aesthetically pleasing?

I'm not that knowledgeable, so would anyone begrudge me deliberately forcing GetEnvironmentVariable to fail in order to get a string size? Does anyone see a problem with:

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

Any other ideas or any suggestions? (Or corrections to glaring mistakes?)

UPDATE: Lots of useful information below. I think the best bet for what I'm trying to do is to use a static char[] like:

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
 }

Perhaps it's not the most elegant way of doing it, but it's probably the easiest way to sync up what I want to do between *nix and Windows. (I'll also worry about Unicode support later.)

Thanks for the help guys.

解决方案

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

Of course, if you want ASCII, replace wstring with string and GetEnvironmentVariableW with GetEnvironmentVariableA.

EDIT: You could also create getenv yourself. This works because

The same memory location may be used in subsequent calls to getenv, overwriting the previous content.

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

Of course, it would probably be a good idea to use the wide character versions of all of this if you want to maintain unicode support.

这篇关于如何使用VS C + + GetEnvironmentVariable尽可能干净?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆