65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 EnumProcess 进行进程创建通知

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.67/5 (2投票s)

2009年6月29日

CPOL

1分钟阅读

viewsIcon

30694

downloadIcon

505

使用 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;
}

欢迎提出评论。

© . All rights reserved.