BSOne.SFC/Tocsg.Module/Bs1Flt/bs1fltctrl/process_notify.cpp

244 lines
5.4 KiB
C++

\
#include "pch.h"
#include "process_notify.h"
#include "psapi.h"
#include "vector"
#include "algorithm"
#include "strsafe.h"
#pragma comment(lib, "Psapi.lib")
CProcessNotify::CProcessNotify()
:
m_hThread(NULL),
m_hQuit(NULL)
{
}
CProcessNotify::~CProcessNotify()
{
FinishPrivate();
}
BOOL CProcessNotify::Start(DWORD nEnumInterval, BOOL bNotifyCurrent, fnNotifyCallBack cb, BOOL bOnce)
{
if (m_hThread)
return TRUE;
if (!m_hQuit)
{
m_hQuit = CreateEvent(NULL, TRUE, FALSE, NULL);
if (!m_hQuit)
return FALSE;
}
m_bOnce = bOnce;
m_nEnumInterval = nEnumInterval;
m_bNotifyCurrent = bNotifyCurrent;
m_cb = cb;
DWORD nThreadId = 0;
m_hThread = CreateThread(NULL, 0, ProcessNotifyProc, (PVOID)this, 0, &nThreadId);
if (!m_hThread)
return FALSE;
return TRUE;
}
DWORD
CProcessNotify::StartPrivate()
{
typedef std::vector<DWORD> PIDLIST;
typedef std::vector<DWORD>::iterator PIDLISTITER;
const DWORD nSize = 1024;
PIDLIST vPidListPrev;
DWORD dwInterval = 1;
for (;;)
{
// ÃÖÃÊ´Â ¹Ù·Î ½ÃÀÛ
DWORD nRet = WaitForSingleObject(m_hQuit, dwInterval);
if (WAIT_TIMEOUT != nRet)
return nRet;
dwInterval = m_nEnumInterval;
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 (!nRet)
continue;
}
PIDLISTITER it;
PIDLIST vPidListAdded(nSize);
PIDLISTITER itAdded = set_difference(vPidListNext.begin(), vPidListNext.end(), vPidListPrev.begin(), vPidListPrev.end(), vPidListAdded.begin());
for (it = vPidListAdded.begin(); it != itAdded; it++)
{
BOOL bRet = OnNotify(*it, TRUE);
if (!bRet)
return ERROR_CANCELLED;
DWORD nRet = WaitForSingleObject(m_hQuit, 0);
if (nRet != WAIT_TIMEOUT)
return nRet;
}
PIDLIST vPidListRemoved(nSize);
PIDLISTITER itRemoved = set_difference(vPidListPrev.begin(), vPidListPrev.end(), vPidListNext.begin(), vPidListNext.end(), vPidListRemoved.begin());
for (it = vPidListRemoved.begin(); it != itRemoved; it++)
{
BOOL bRet = OnNotify(*it, FALSE);
if (!bRet)
return ERROR_CANCELLED;
DWORD nRet = WaitForSingleObject(m_hQuit, 0);
if (nRet != WAIT_TIMEOUT)
return nRet;
}
vPidListPrev = vPidListNext;
if (m_bOnce)
break;
}
return 0;
}
DWORD WINAPI CProcessNotify::ProcessNotifyProc(LPVOID pArg)
{
CProcessNotify* pProcessNotify = reinterpret_cast<CProcessNotify*>(pArg);
if (!pProcessNotify)
{
return ERROR_INVALID_PARAMETER;
}
return pProcessNotify->StartPrivate();
}
BOOL
CProcessNotify::Finish()
{
return FinishPrivate();
}
BOOL
CProcessNotify::FinishPrivate()
{
if (!m_hThread)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if (m_hQuit)
{
SetEvent(m_hQuit);
}
WaitForSingleObject(m_hThread, INFINITE);
CloseHandle(m_hThread);
CloseHandle(m_hQuit);
m_hThread = NULL;
m_hQuit = NULL;
return TRUE;
}
BOOL GetProcessFullPath(DWORD dwPid, LPWSTR lpwProcessFullPath, DWORD dwSize)
{
static ZWQUERYINFORMATIONPROCESS query = NULL;
NTSTATUS dwError = 0;
HANDLE hProcess = NULL;
DWORD dwReturnSize = 0;
DWORD bufsize = dwReturnSize;
PVOID* buf = NULL;
PUNICODE_STRING pUni = NULL;
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwPid);
if (hProcess == NULL)
{
return FALSE;
}
if (query == NULL)
{
query = (ZWQUERYINFORMATIONPROCESS)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtQueryInformationProcess");
}
dwError = query(hProcess, ProcessImageFileName, NULL, 0, &dwReturnSize);
if (dwError != STATUS_INFO_LENGTH_MISMATCH)
{
goto $GetProcessFullPathCleanup;
}
buf = (PVOID*)malloc(bufsize);
if (!buf)
goto $GetProcessFullPathCleanup;
memset(buf, 0, bufsize);
dwError = query(hProcess, ProcessImageFileName, buf, bufsize, &dwReturnSize);
if (dwError != 0)
{
goto $GetProcessFullPathCleanup;
}
pUni = (PUNICODE_STRING)buf;
//OutputDebugStringW(pUni->Buffer);
StringCbCopyNW(lpwProcessFullPath, dwSize, pUni->Buffer, pUni->Length);
$GetProcessFullPathCleanup:
if (hProcess)
CloseHandle(hProcess);
if (buf)
free(buf);
return TRUE;
}
BOOL
CProcessNotify::OnNotify(DWORD nPid, BOOL bCreate)
{
if (bCreate)
{
WCHAR FileName[1024] = { 0, };
BOOL i = GetProcessFullPath(nPid, FileName, sizeof(FileName));
m_cb(bCreate, nPid, FileName, (DWORD)wcslen(FileName));
}
else
{
m_cb(bCreate, nPid, NULL, 0);
}
return TRUE;
}