首页 > 代码库 > windows - 进程 - 进程环境变量

windows - 进程 - 进程环境变量

原文链接1 原文链接2

1.进程的环境变量

每个进程都有一个与它关联的环境块(environment block),这是在进程地址空间内分配的一块内存,其中包含字符串类似于:

=::=::\...

VarName=VarValue\0...

\0

除第一个=::=::\外,块中可能还有其他字符串是以等号开头的,这种字符串不作为环境变量使用。

访问环境块的两种方式:

1)调用GetEnvironmentStrings获取完整的环境块

2)CUI程序专用,通过应用程序main入口点函数所接收的TCHAR* env[]参数来实现


2.调用GetEnvironmentStrings获取完整的环境块

1)不论是不是环境变量,暂且都打印出来

[cpp] view plaincopyprint?
  1. void DumpEnvStrings()  
  2. {  
  3.     PTSTR pEnvBlock = GetEnvironmentStrings();  
  4.   
  5.     PTSTR pszCurrent = pEnvBlock;  
  6.     int current = 0;  
  7.   
  8.     while (pszCurrent != NULL)  
  9.     {  
  10.         // 不论是不是环境变量,暂且都打印  
  11.         _tprintf(TEXT("[%u] %s\r\n"), current, pszCurrent);  
  12.   
  13.         current++;  
  14.   
  15.         // 指针移动到字符串末尾  
  16.         while (*pszCurrent != TEXT(‘\0‘))  
  17.             pszCurrent++;  
  18.         pszCurrent++;  
  19.   
  20.         // 是否是最后一个字符串  
  21.         if (*pszCurrent == TEXT(‘\0‘))  
  22.             break;  
  23.     }  
  24.   
  25.     // 释放内存  
  26.     FreeEnvironmentStrings(pEnvBlock);  
  27. }  
技术分享

2)去除无意义的串

[cpp] view plaincopyprint?
  1. void DumpEnvStrings()  
  2. {  
  3.     PTSTR pEnvBlock = GetEnvironmentStrings();  
  4.       
  5.     TCHAR szName[MAX_PATH];  
  6.     TCHAR szValue[MAX_PATH];  
  7.     PTSTR pszCurrent = pEnvBlock;  
  8.     HRESULT hr = S_OK;  
  9.     PCTSTR pszPos = NULL;  
  10.     int current = 0;  
  11.   
  12.     while (pszCurrent != NULL)  
  13.     {  
  14.         // 去除无意义的串(以‘=‘开头,如"=::=::\","=C:=C:Windows\System32")  
  15.         if (*pszCurrent != TEXT(‘=‘))  
  16.         {  
  17.             // 查找‘=‘,然后指针指向‘=‘后一个字符,即值的第一个字符  
  18.             pszPos = _tcschr(pszCurrent, TEXT(‘=‘));  
  19.             pszPos++;  
  20.   
  21.             // 将变量名拷贝到szName  
  22.             size_t cbNameLength = (size_t)pszPos - (size_t)pszCurrent - sizeof(TCHAR);  
  23.             hr = StringCbCopyN(szName, MAX_PATH, pszCurrent, cbNameLength);  
  24.             if (FAILED(hr)) {  
  25.                 break;  
  26.             }  
  27.   
  28.             // 获取值  
  29.             hr = StringCbCopyN(szValue, MAX_PATH, pszPos, _tcslen(pszPos)+1);  
  30.             if (SUCCEEDED(hr)) {  
  31.                 _tprintf(TEXT("[%u] %s=%s\r\n"), current, szName, szValue);  
  32.             }  
  33.             else if (hr == STRSAFE_E_INSUFFICIENT_BUFFER){  
  34.                 // 发生错误,检查截断  
  35.                 _tprintf(TEXT("[%u] %s=%s...\r\n"), current, szName, szValue);  
  36.             }  
  37.             else {  
  38.                 // 这里应该不能发生  
  39.                 _tprintf(TEXT("[%u] %s=???\r\n"), current, szName);  
  40.                 break;  
  41.             }  
  42.         }  
  43.         else {  
  44.             _tprintf(TEXT("[%u] %s\r\n"), current, pszCurrent);  
  45.         }  
  46.   
  47.         current++;  
  48.   
  49.         // 指针移动到字符串末尾  
  50.         while (*pszCurrent != TEXT(‘\0‘))  
  51.             pszCurrent++;  
  52.         pszCurrent++;  
  53.   
  54.         // 是否是最后一个字符串  
  55.         if (*pszCurrent == TEXT(‘\0‘))  
  56.             break;  
  57.     }  
  58.   
  59.     // 释放内存  
  60.     FreeEnvironmentStrings(pEnvBlock);  
  61. }  

技术分享


3.通过应用程序main入口点函数所接收的TCHAR* env[]参数来实现

[cpp] view plaincopyprint?
  1. void DumpEnvVariables(PTSTR pEnvBlock[])  
  2. {  
  3.     int current = 0;  
  4.     PTSTR* pElement = (PTSTR*)pEnvBlock;  
  5.     PTSTR pCurrent = NULL;  
  6.     while (pElement != NULL)  
  7.     {  
  8.         pCurrent = (PTSTR)(*pElement);  
  9.         if (pCurrent == NULL)  
  10.         {  
  11.             // 没有更多环境变量了  
  12.             pElement = NULL;  
  13.         }  
  14.         else  
  15.         {  
  16.             _tprintf(TEXT("[%u] %s\r\n"), current, pCurrent);  
  17.             current++;  
  18.             pElement++;  
  19.         }  
  20.     }  
  21. }  
  22.   
  23. int _tmain()  
  24. {  
  25.     DumpEnvVariables(_wenviron);  
  26.     return 0;  
  27. }  

技术分享


环境变量是进程中一组变量信息,环境变量分为系统环境变量、用户环境变量和进程环境变量。系统有全局的环境变量,在进程创建时,进程继承了系统的全局环境变量、当前登录用户的用户环境变量和父进程的环境变量。进程也可以有自己的环境变量。

设置和获取所在进程的环境变量使用API函数GetEnvironmentStrings、GetEnvironmentVariable和SetEnvironmentVariable:

1)GetEnvironmentStrings函数用于获取所有环境变量字符串:

LPTCH WINAPI GetEnvironmentStrings(void);

返回值:

成功时,返回指向保存环境变量的缓冲区;

失败时,返回值为NULL。

 

2)FreeEnvironmentStrings函数用来释放由GetEnvironmentStrings返回的内存块:

BOOL WINAPI FreeEnvironmentStrings(

  __in  LPTCH lpszEnvironmentBlock

);

返回值:

成功时,返回非零值;

失败时,返回零值,可调用GetLastError()查看进一步错误消息。

 

3)GetEnvironmentVariable函数用于获取指定的环境变量:

DWORD WINAPI GetEnvironmentVariable(

  __in_opt   LPCTSTR lpName, //环境变量名

  __out_opt  LPTSTR lpBuffer, //指向保存环境变量值的缓冲区

  __in       DWORD nSize //缓冲区大小(字符数)

);

返回值:

成功时,返回真实的环境变量值大小,不包括null结束符;

如果lpBuffer大小不足,则返回值是实际所需的字符数大小,lpBuffer内容未定义;

失败时,返回0;如果指定的环境变量找不到,GetLastError()返回ERROR_ENVVAR_NOT_FOUND。

 

4)SetEnvironmentVariable函数用于设置指定的环境变量:

BOOL WINAPI SetEnvironmentVariable(

  __in      LPCTSTR lpName, //环境变量名,当该值不存在且lpValue不为NULL时,将创建一个新的

  __in_opt  LPCTSTR lpValue //环境变量值

);

返回值:

成功时,返回非零值;

失败时,返回零值,调用GetLastError()查看具体的错误信息。

该函数对系统环境变量以及其他进程的环境变量不起作用!

 

实例一:调用GetEnvironmentStrings函数检索进程的环境变量内存块,并将其中内容打印到控制台:

#include <windows.h>
#include <tchar.h>
#include <stdio.h>

int _tmain()
{
	LPTSTR lpszVariable;
	LPTCH lpvEnv;

	// Get a pointer to the environment block. 

	lpvEnv = GetEnvironmentStrings();

	// If the returned pointer is NULL, exit.
	if (lpvEnv == NULL)
	{
		printf("GetEnvironmentStrings failed (%d)\n",
			GetLastError());
		return 0;
	}

	// Variable strings are separated by NULL byte, and the block is 
	// terminated by a NULL byte. 

	lpszVariable = (LPTSTR)lpvEnv;

	while (*lpszVariable)
	{
		_tprintf(TEXT("%s\n"), lpszVariable);
		lpszVariable += lstrlen(lpszVariable) + 1;
	}
	FreeEnvironmentStrings(lpvEnv);
	return 1;
}


 

实例二:默认情况下,子进程继承父进程环境变量内存块的一份拷贝;下面代码通过调用CreateProcess函数实现将一个环境变量块传递给子进程(asce.exe就是实例一编译链接得到的exe文件,因此,该代码的运行结果就是子进程打印从父进程继承而来的环境变量):

 

#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <strsafe.h>

#define BUFSIZE 4096

VOID GetAppPath(LPTSTR pszBuffer)
{
	DWORD dwLen = 0;
	if (0 == (dwLen = ::GetModuleFileName(NULL, pszBuffer, MAX_PATH)))
	{
		return;
	}
	DWORD i = dwLen;
	for (; i > 0; i--)
	{
		if ('\\' == pszBuffer[i])
		{
			pszBuffer[i + 1] = '\0';
			break;
		}
	}
}
int _tmain()
{
	TCHAR chNewEnv[BUFSIZE];
	LPTSTR lpszCurrentVariable;
	DWORD dwFlags = 0;
//	TCHAR szAppName[] = TEXT("GetEnvironmentStrings.exe");
	TCHAR pszAppPath[MAX_PATH + 1] = {};
	TCHAR pszExe[MAX_PATH + 1] = {};
	GetAppPath(pszAppPath);
	STARTUPINFO si;
	PROCESS_INFORMATION pi;
	BOOL fSuccess;

	//将环境变量字符串拷贝到环境变量内存块中
	lpszCurrentVariable = (LPTSTR)chNewEnv;
	if (FAILED(StringCchCopy(lpszCurrentVariable, BUFSIZE, TEXT("AsceSetting=Luffy"))))
	{
		printf("String copy failed/n");
		return FALSE;
	}

	lpszCurrentVariable += lstrlen(lpszCurrentVariable) + 1;

	if (FAILED(StringCchCopy(lpszCurrentVariable, BUFSIZE, TEXT("AsceVersion=2.0"))))
	{
		printf("String copy failed/n");
		return FALSE;
	}

	//使环境变量内存块以NULL结尾
	lpszCurrentVariable += lstrlen(lpszCurrentVariable) + 1;
	*lpszCurrentVariable = (TCHAR)0;

	//创建子进程,指定一个新的环境变量内存块
	SecureZeroMemory(&si, sizeof(STARTUPINFO));
	si.cb = sizeof(STARTUPINFO);

#ifdef UNICODE
	dwFlags = CREATE_UNICODE_ENVIRONMENT;
#endif

	StringCchPrintf(pszExe, MAX_PATH, _T("%s%s"), pszAppPath, _T("GetEnvironmentStrings.exe"));
	fSuccess = CreateProcess(pszExe, NULL, NULL, NULL,
		TRUE, dwFlags, (LPVOID)chNewEnv, //新的环境变量内存块
		NULL, &si, &pi);
	if (!fSuccess)
	{
		printf("CreateProcess failed(%d)/n", GetLastError());
		return FALSE;
	}
	WaitForSingleObject(pi.hProcess, INFINITE);
	system("pause");
	return TRUE;
}

实例三:在子进程创建过程中改变子进程的环境变量是一个进程改变另一个进程环境变量的唯一方式。一个进程绝不能直接改变另一个进程(非子进程)的环境变量。下面代码实现子进程继承符进程环境变量的方法:

#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <strsafe.h>
#define BUFSIZE 4096
#define VARNAME TEXT("MyVariable")

VOID GetAppPath(LPTSTR pszBuffer)
{
	DWORD dwLen = 0;
	if (0 == (dwLen = ::GetModuleFileName(NULL, pszBuffer, MAX_PATH)))
	{
		return;
	}
	DWORD i = dwLen;
	for (; i > 0; i--)
	{
		if ('\\' == pszBuffer[i])
		{
			pszBuffer[i + 1] = '\0';
			break;
		}
	}
}
int _tmain()
{
	DWORD dwRet, dwErr;
	LPTSTR pszOldVal;
	//TCHAR szAppName[] = TEXT("ex3.exe");
	TCHAR pszAppPath[MAX_PATH + 1] = {};
	TCHAR pszExe[MAX_PATH + 1] = {};
	GetAppPath(pszAppPath);
	DWORD dwFlags = 0;
	STARTUPINFO si;
	PROCESS_INFORMATION pi;
	BOOL fExist, fSuccess;

	// Retrieves the current value of the variable if it exists.
	// Sets the variable to a new value, creates a child process,
	// then uses SetEnvironmentVariable to restore the original
	// value or delete it if it did not exist previously. 

	pszOldVal = (LPTSTR)malloc(BUFSIZE*sizeof(TCHAR));
	if (NULL == pszOldVal)
	{
		printf("Out of memory\n");
		return FALSE;
	}

	dwRet = GetEnvironmentVariable(VARNAME, pszOldVal, BUFSIZE);

	if (0 == dwRet)
	{
		dwErr = GetLastError();
		if (ERROR_ENVVAR_NOT_FOUND == dwErr)
		{
			printf("Environment variable does not exist.\n");
			fExist = FALSE;
		}
	}
	else if (BUFSIZE < dwRet)
	{
		pszOldVal =
			(LPTSTR)realloc(pszOldVal, dwRet*sizeof(TCHAR));
		if (NULL == pszOldVal)
		{
			printf("Out of memory\n");
			return FALSE;
		}
		dwRet = GetEnvironmentVariable(VARNAME, pszOldVal, dwRet);
		if (!dwRet)
		{
			printf("GetEnvironmentVariable failed (%d)\n",
				GetLastError());
			return FALSE;
		}
		else fExist = TRUE;
	}
	else fExist = TRUE;

	// Set a value for the child process to inherit. 

	if (!SetEnvironmentVariable(VARNAME, TEXT("Test")))
	{
		printf("SetEnvironmentVariable failed (%d)\n",
			GetLastError());
		return FALSE;
	}

	// Create a child process. 

	SecureZeroMemory(&si, sizeof(STARTUPINFO));
	si.cb = sizeof(STARTUPINFO);

#ifdef UNICODE
	dwFlags = CREATE_UNICODE_ENVIRONMENT;
#endif

	StringCchPrintf(pszExe, MAX_PATH, _T("%s%s"), pszAppPath, _T("GetEnvironmentStrings.exe"));
	fSuccess = CreateProcess(
		pszExe, NULL, NULL, NULL, TRUE, dwFlags,
		NULL,     // inherit parent's environment 
		NULL, &si, &pi);
	if (!fSuccess)
	{
		printf("CreateProcess failed (%d)\n", GetLastError());
	}
	WaitForSingleObject(pi.hProcess, INFINITE);

	// Restore the original environment variable. 

	if (fExist)
	{
		if (!SetEnvironmentVariable(VARNAME, pszOldVal))
		{
			printf("SetEnvironmentVariable failed (%d)\n",
				GetLastError());
			return FALSE;
		}
	}
	else SetEnvironmentVariable(VARNAME, NULL);

	return fSuccess;
}
上面的参考与网上 还有MSDN  GetEnvironmentStrings Function
直接使用xxxx.exe 创建失败

获得路径的源码

VOID GetAppPath(LPTSTR pszBuffer)
{
	DWORD dwLen = 0;
	if (0 == (dwLen = ::GetModuleFileName(NULL, pszBuffer, MAX_PATH)))
	{
		return;
	}
	DWORD i = dwLen;
	for (; i > 0; i--)
	{
		if ('\\' == pszBuffer[i])
		{
			pszBuffer[i + 1] = '\0';
			break;
		}
	}
}
	TCHAR pszAppPath[MAX_PATH + 1] = {};
	TCHAR pszExe[MAX_PATH + 1] = {};
	GetAppPath(pszAppPath);
	StringCchPrintf(pszExe, MAX_PATH, _T("%s%s"), pszAppPath, _T("SubGUI.exe"));

作者:locojyw
email:locojyw@outlook.com
欢迎大家交流,有什么错误请指出
转载注明出处

windows - 进程 - 进程环境变量