Win64Visual C++ 9.0STLVisual C++ 7.1Visual C++ 8.0Visual C++ 7.0Win32Visual Studio 2008设计 / 图形Visual C++ 6.0架构师高级初级C中级开发Visual StudioWindowsC++
使用 EnumProcess 进行进程创建通知
使用 EnumProcess 轮询以在用户模式下获取进程创建通知。
 
 
引言
Windows 在用户模式下没有提供基于事件的进程相关通知机制。因此,任何解决方案本质上都是基于轮询的。一种选择是使用 EnumProcess API。也可以使用 WMI。我从未用过 WMI,所以无法说明使用基于 WMI 的方法的开销。但有一点是肯定的,使用 WMI 会带来对 WMI 服务的额外依赖。在本文中,我将考虑基于 EnumProcess 的方法。请参阅 此处 获取基于 WMI 的方法。
Using the Code
示例类 CProcessNotify 封装了 EnumProcess 轮询功能。在单独的线程中以用户提供的间隔进行轮询。通知在该线程中传递。但是,如果您需要调用线程阻塞,可以修改该类以适应您的目的。这是主要代码。基本上,使用 STL set_compare 比较从 EnumProcess 返回的进程 ID 列表。当前列表和先前列表的差异给出了创建和终止的 ID。当前方法有一个小缺点。如果一个进程消失,并且在轮询间隔内出现一个具有相同 ID 的新进程,它将无法识别。对此的解决方法是使用 GetProcessTimes API 存储进程启动时间以及 ID。
typedef std::vector<dword> PIDLIST;
typedef std::vector<dword>::iterator PIDLISTITER;
const DWORD nSize = 1024;
PIDLIST vPidListPrev;
for (;;)
{
	DWORD nRet = WaitForSingleObject(
		m_hQuit,
		m_nEnumInterval);
	if (WAIT_TIMEOUT != nRet)
	{
		return nRet;
	}
	PIDLIST vPidListNext(nSize);
	DWORD nNeeded = 0;
	BOOL bRet = EnumProcesses(
		&vPidListNext[0],
		nSize*sizeof(DWORD),
		&nNeeded);
	if (!bRet)
	{
		return GetLastError();
	}
	vPidListNext.resize(nNeeded / sizeof(DWORD));
	sort(
		vPidListNext.begin(),
		vPidListNext.end());
	if (vPidListPrev.empty())
	{
		if (!m_bNotifyCurrent)
		{
			vPidListPrev = vPidListNext;
			continue;
		}
	}
	if (vPidListNext.size() == vPidListPrev.size())
	{
		int nRet = memcmp(
			&vPidListNext[0],
			&vPidListPrev[0],
			nNeeded);
		if (0 == nRet)
		{
			continue;
		}
	}
	PIDLIST vPidListAdded(nSize);
	PIDLISTITER itAdded = set_difference(
		vPidListNext.begin(),
		vPidListNext.end(),
		vPidListPrev.begin(),
		vPidListPrev.end(),
		vPidListAdded.begin());
	for (PIDLISTITER it1 = vPidListAdded.begin() ; it1 != itAdded ; it1++)
	{
		BOOL bRet = OnNotify(*it1, TRUE);
		if (!bRet)
		{
			return ERROR_CANCELLED;
		}
		DWORD nRet = WaitForSingleObject(
			m_hQuit,
			0);
		if (WAIT_TIMEOUT != nRet)
		{
			return nRet;
		}
	}
	PIDLIST vPidListRemoved(nSize);
	PIDLISTITER itRemoved = set_difference(
		vPidListPrev.begin(),
		vPidListPrev.end(),
		vPidListNext.begin(),
		vPidListNext.end(),
		vPidListRemoved.begin());
	for (PIDLISTITER it1 = vPidListRemoved.begin() ; it1 != itRemoved ; it1++)
	{
		BOOL bRet = OnNotify(*it1, FALSE);
		if (!bRet)
		{
			return ERROR_CANCELLED;
		}
		DWORD nRet = WaitForSingleObject(
			m_hQuit,
			0);
		if (WAIT_TIMEOUT != nRet)
		{
			return nRet;
		}
	}
	vPidListPrev = vPidListNext;
}
欢迎提出评论。




