windows核心编程(四) 关于进程

(1)定义

进程定义成一个正在运行的程序的一个实例,创建进程后会生成一个内核对象,操作系统使用它来管理进程,也是用它来保存进程统计信息的地方。

另外,进程的创建,操作系统会为它分配一块独立的地址空间,包含所有可执行的文件或DLL模块代码或者数据,还包括动态内存分配,例如:线程堆栈和堆的分配。

(2)进程实例句柄(HMODULE和HINSTANCE是一回事)

	GetModuleFileName();//获取模块的文件路径,首参数为NULL时,获取的是当前进程的文件所在的路径
	GetModuleHandle();//获取模块的句柄,参数为NULL时,获取当前进程的文件的句柄
(3)进程的环境变量
每个进程都有一个与它关联的进程块(environment block),这是在地址空间内分配的一块内存。

	LPTCH lptch = GetEnvironmentStrings(); //获取完整的环境块
	FreeEnvironmentStrings(lptch);//使用环境块完成后需要释放
windows系统登录以后,会检查注册表中的两个注册表项来获得初始的环境变量:
(a)[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment]
对应的是系统环境变量的系统变量
(b)[HKEY_CURRENT_USER\Environment]
对应的是系统的环境变量的用户变量
注:当在注册表内修改了环境变得的数据时,必须重启机器时使其更改生效。

有的应用程序(资源管理器,任务管理器,控制面板)可以在其主窗口收到WM_SETTINGCHANGE消息的时候,更新他们的环境块。使用如下的命令:

	SendMessage(HWND_BROADCAST,WM_SETTINGCHANGE,0,(LPARAM)TEXT("Environment"));
	//判断一个环境变量是否存在,使用如下函数:
	DWORD WINAPI GetEnvironmentVariable(
	  __in          LPCTSTR lpName,
	  __out         LPTSTR lpBuffer,
	  __in          DWORD nSize
	);
	//使用如下函数来设置一个环境变量的值,若值设为NULL,则在环境块中删除此变量。
	BOOL WINAPI SetEnvironmentVariable(
	  __in          LPCTSTR lpName,
	  __in          LPCTSTR lpValue
	);
	//对于%XXXX%形式的字符换,使用如下函数展开:
	DWORD WINAPI ExpandEnvironmentStrings(
	  __in          LPCTSTR lpSrc,
	  __out         LPTSTR lpDst,
	  __in          DWORD nSize
	);
(4)进程当前所在的驱动器和目录
假如CreateFile一个文件,当参数传递的文件路径不是绝对路径时,系统只能在当前驱动器和目录下查找该文件。
系统在内部跟踪记录着一个进程的当前驱动器和目录。由于这种信息是以进程为单位来维护的,所以若进程内的一个线程更改了当前驱动器和目录,则进程内的所有线程的驱动器和目录都改变了。
使用如下函数来获取一个当前进程的驱动器和目录(WinDef.h文件中定义MAX_PATH为目录名称和驱动名称的最大的字符数):

DWORD WINAPI GetCurrentDirectory(
  __in          DWORD nBufferLength,
  __out         LPTSTR lpBuffer
);

//使用如下的函数来设置:
BOOL WINAPI SetCurrentDirectory(
  __in          LPCTSTR lpPathName
);//参数包括驱动器符号和目录
(5)创建进程函数:

BOOL WINAPI CreateProcess(
  __in          LPCTSTR lpApplicationName,
  __in_out      LPTSTR lpCommandLine,
  __in          LPSECURITY_ATTRIBUTES lpProcessAttributes,
  __in          LPSECURITY_ATTRIBUTES lpThreadAttributes,
  __in          BOOL bInheritHandles,
  __in          DWORD dwCreationFlags,
  __in          LPVOID lpEnvironment,
  __in          LPCTSTR lpCurrentDirectory,
  __in          LPSTARTUPINFO lpStartupInfo,
  __out         LPPROCESS_INFORMATION lpProcessInformation
);
(5。1)lpApplicationName和lpCommandLine
要开打的应用程序的名字和参数。第一种设置方式:可以指定lpAppliationName为NULL,在lpCommandLine 以使用完整的应用程序名称加参数的形式来传递。第二种指定方式:lpAppliationName传递应用程序的路径,lpCommandLine传递参数。
注:lpCommandLine的参数类型为LPTSTR,也就是说不能讲一个字符串常量传递进去。进程内部会修改这个参数变量,在结束时还会修改回来。必须将其参数保存到临时存储区再以参数方式传递。
(5。2) lpProcessAttributes和lpThreadAttributes
创建一个新的进程,系统必须创建一个进程内核对象和一个线程内核对象,父进程有机会将内核对象的安全数据关联到这两个内核对象上。若都传递NULL,则系统将设置为内核对象分配默认的安全描述符属性。
(5。3)bInheritHandles
若为TRUE:则子进程会继承父进程中所有可以被继承的对象(不仅仅是内核对象???)的句柄。
若为FALSE:则子进程不会继承父进程的任何对象的句柄。
(5。4)dwCreationFlags
影响了新进程创建方式的标志。一般使用最多的是CREATE_SUSPENDED,表示创建完成后将子进程先挂起,直到父进程调用ResumeThread();函数使其进程的主线程开始执行。
(5。5)lpEnvironment
表示新进程要使用的字符串环境变量,此函数为NULL时,子进程将继承其父进程使用的环境变量。和使用GetEnvironmentStrings()函数返回的地址作为参数是相同的。
(5。6)lpCurrentDirectory
设置子进程的驱动器和目录。此参数为NULL时,子进程使用和父进程的相同的驱动器和目录。若不为NULL,则必须是一个包含驱动器符号的以'\0'结束的字符串。(必须包含一个驱动器号)
(5。7)lpStartupInfo
该结构参数用于指定新进程的主窗口的特性。
一般使用默认,使用如下初始化即可:

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

(5。8)lpProcessInformation(输出参数)
在createProcess函数返回之前,会填充这个结构体。包含子进程的进程和主线程的句柄、进程和主线程的ID。
可以使用如下相关的方法获取句柄和ID:

	GetCurrentProcessId(); //获取当前的进程的ID
	GetCurrentThreadId();//获取当前的线程的ID
	GetProcessId();//通过句柄获取进程的ID
	GetProcessIdOfThread();//通过线程的ID获取所在进程的ID
	Toolhelp32ReadProcessMemory();//没使用过这个,用的时候再去了解
(6)终止进程
(6。1)主线程的入口函数返回(强烈推荐方式)
该过程会非常完美的将进程结束掉,主要做:(a)所有的C++的对象会调用析构函数来销毁c++对象。(b)正确释放线程栈使用的内存。(c)递减所有使用的内核对象的使用计数。(d)设置退出码。
(6。2)进程中的一个线程调用函数ExitProcess()函数。(避免使用)
调用ExitProcess和ExitThread此类函数会直接导致进程或者线程的终止。对于操作系统而言没什么问题,进程或者线程的所有操作系统资源都会被清理。但是C/C++程序不能进行正确的清理工作。
(6。3)另一个进程中的线程调用TreatmentProcess()函数。(避免使用)
被终止的进程得不到自己要被 终止的通知---应用程序不能正确的清理,也不能阻止他自己被强行终止(除非通过正常的安装机制)。进程无法将它在内存的信息刷新到磁盘上。
进程的终止以后不会泄露任何东西。操作系统在进程终止以后会进行彻底的清理,确保不会泄露任何操作系统的资源。
(6。4)进程中的所有线程都“自然死亡”。(几乎从来不会出现。)
进程内的所有的线程都终止了,返回码为最后一个终止线程的退出码。
(7)创建子进程
	//创建子进程
	PROCESS_INFORMATION pi;
	DWORD dwExitCode;
	BOOL bSuccess = CreateProcess(....,pi);
	if (bSuccess)
	{
		//
		CloseHandle(pi.dwThreadId);
		
		WaitForSingleObject(pi.dwProcessId,INFINITE);
		GetExitCodeProcess(pi.dwProcessId,dwExitCode);
		CloseHandle(pi.dwProcessId);
	}
	//创建子进程后,不再与父进程联系,则创建后关闭子进程的进程句柄和主线程句柄
	PROCESS_INFORMATION pi;
	DWORD dwExitCode;
	BOOL bSuccess = CreateProcess(....,pi);
	if (bSuccess)
	{
		CloseHandle(pi.dwThreadId);		
		CloseHandle(pi.dwProcessId);
	}
(8)进程运行权限(vista以上的版本的系统)
(8。1)在vs里面设置应用程序使用系统管理员权限运行,设置方法如下:
工程---属性---配置属性---链接器---清单文件--UAC设置级别 设置为:RequireAdministrator
(8。2)在运行时,手动提升进程的权限,使用的函数是ShellExecuteEx(),如下介绍:

	//此函数参数的结构体内的成员: 
	LPCTSTR lpVerb; //设置为“runas”
    LPCTSTR lpFile; //设置为运行的进程的路径名称
	//此时,运行时,会弹出权限访问的窗口。
(8。3)当前权限上下文
仅仅看个例子吧,不是太清楚。
BOOL GetProcessElevation(TOKEN_ELEVATION_TYPE  *pElevationType,
						 BOOL *pIsAdmin)
{
	HANDLE hTocken = NULL;
	DWORD dwSize;

	//获取当前进程令牌
	if (!OpenProcessToken(GetCurrentProcess(),TOKEN_QUERY,&hTocken))
	{
		return FALSE;
	}

	BOOL bResult = FALSE;
	//检索提升的类型信息
	if(GetTokenInformation(hTocken,TokenElevationType,pElevationType,sizeof(TOKEN_ELEVATION_TYPE),&dwSize))
	{
		//创建sid对应管理员组
		BYTE adminSID[SECURITY_MAX_SID_SIZE];
		dwSize = sizeof(adminSID);
		CreateWellKnownSid(WinBuiltinAdministratorsSid,NULL,&adminSID,&dwSize);

		CString csLog;
		csLog.Format(_T("*pElevationType;%d"),*pElevationType);
		AfxMessageBox(csLog);
		if (*pElevationType == TokenElevationTypeLimited)
		{
			//得到连接令牌的句柄(will have one if we are lua)
			HANDLE hUnfilteredToken = NULL;
			GetTokenInformation(hTocken,TokenLinkedToken,(void*)&hUnfilteredToken,sizeof(HANDLE),&dwSize);
			//检查这个原始的令牌是否包含admin 的SID
			if(CheckTokenMembership(hUnfilteredToken,&adminSID,pIsAdmin))
			{
				bResult = TRUE;
			}

			//不要忘记关闭这个hUnfilteredToken句柄
			CloseHandle(hUnfilteredToken);
		}else
		{
			*pIsAdmin = IsUserAnAdmin();
			bResult = TRUE;
		}
	}
	//不要忘记关闭进程的令牌
	CloseHandle(hTocken);

	return (bResult);
}

void CMFC_DIAloGDlg::OnBnClickedButton4()
{
	// TODO: 在此添加控件通知处理程序代码

	BOOL bAdmin = FALSE;
	TOKEN_ELEVATION_TYPE tet;
	GetProcessElevation(&tet ,&bAdmin);

	
	if (bAdmin)
	{
		AfxMessageBox(_T("使用的是管理员权限运行"));

	}else
	{
		AfxMessageBox(_T("使用的非管理员权限运行"));
	}
	CString csLog;
	csLog.Format(_T("tet:%d bAdmin:%d "),tet,bAdmin);
	AfxMessageBox(csLog);
}
(9)枚举系统中正在运行的进程
win95、win98版本及以上提供的函数:

	Process32First();
	Process32Next();
windows NT 提供的函数:
EnumProcesses();下面是MSDN上的例子:

#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#include <psapi.h>
#pragma comment(lib,"Psapi.lib")
void PrintProcessNameAndID( DWORD processID )
{
	TCHAR szProcessName[MAX_PATH] = TEXT("<unknown>");

	// Get a handle to the process.
	HANDLE hProcess = OpenProcess( PROCESS_QUERY_INFORMATION |
		PROCESS_VM_READ,
		FALSE, processID );

	// Get the process name.
	if (NULL != hProcess )
	{
		HMODULE hMod;
		DWORD cbNeeded;

		if ( EnumProcessModules( hProcess, &hMod, sizeof(hMod), &cbNeeded) )
		{
			GetModuleBaseName( hProcess, hMod, szProcessName, 
				sizeof(szProcessName)/sizeof(TCHAR) );
		}
	}

	// Print the process name and identifier.
	CString cslog;
	cslog.Format( TEXT("%s  (PID: %u)\n"), szProcessName, processID );
	OutputDebugString(cslog);

	CloseHandle( hProcess );
}

void CMFC_DIAloGDlg::OnBnClickedButton4()
{
	// Get the list of process identifiers.
	DWORD aProcesses[1024], cbNeeded, cProcesses;
	unsigned int i;

	if ( !EnumProcesses( aProcesses, sizeof(aProcesses), &cbNeeded ) )
		return;

	// Calculate how many process identifiers were returned.
	cProcesses = cbNeeded / sizeof(DWORD);

	// Print the name and process identifier for each process.
	for ( i = 0; i < cProcesses; i++ )
	{
		if( aProcesses[i] != 0 )
		{
			PrintProcessNameAndID( aProcesses[i] );
		}
	}	
	
}	


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值