2025-04-27 07:49:33 -04:00

1511 lines
42 KiB
C++

// WorkItem.cpp
#include "stdafx.h"
#include "EssTest.h"
#include "WorkItem.h"
#include <flexarry.h>
#include <wbemint.h>
#include <share.h>
#define DEF_EVENTS 1000
#define DEF_REPEAT 1
#define DEF_PERM_CONS 10
#define DEF_TEMP_CONS 1
#define DEF_SLOW_DOWN FALSE
/////////////////////////////////////////////////////////////////////////////
// CWorkItem
CWorkItem::CWorkItem() :
m_bFullCompare(TRUE)
{
}
CWorkItem::~CWorkItem()
{
for (CPConsumerListIterator perm = m_listPermConsumers.begin();
perm != m_listPermConsumers.end();
perm++)
{
delete (*perm);
}
for (CTConsumerListIterator temp = m_listTempConsumers.begin();
temp != m_listTempConsumers.end();
temp++)
{
delete (*temp);
}
for (CWorkFilterListIterator filter = m_listFilters.begin();
filter != m_listFilters.end();
filter++)
{
delete (*filter);
}
if (!g_essTest.KeepLogs() && m_strEventGenFile.length())
DeleteFileW(m_strEventGenFile);
}
HRESULT CWorkItem::Init(IWbemClassObject *pObj, DWORD dwID)
{
HRESULT hr;
_variant_t vTemp;
m_dwID = dwID;
// Load the work item's properties.
if (SUCCEEDED(hr = pObj->Get(L"Name", 0, &vTemp, NULL, NULL)))
{
m_strName = V_BSTR(&vTemp);
if (SUCCEEDED(pObj->Get(L"NumEvents", 0, &vTemp, NULL, NULL)) &&
vTemp.vt == VT_I4)
m_nEvents = (long) vTemp;
else
m_nEvents = DEF_EVENTS;
if (SUCCEEDED(pObj->Get(L"TimesToExecute", 0, &vTemp, NULL, NULL)) &&
vTemp.vt == VT_I4)
m_nTimesToRepeat = (long) vTemp;
else
m_nTimesToRepeat = DEF_REPEAT;
if (SUCCEEDED(pObj->Get(L"MaxPermConsumers", 0, &vTemp, NULL, NULL)) &&
vTemp.vt == VT_I4)
m_nPermConsumers = (long) vTemp;
else
m_nPermConsumers = DEF_PERM_CONS;
if (SUCCEEDED(pObj->Get(L"MaxTempConsumers", 0, &vTemp, NULL, NULL)) &&
vTemp.vt == VT_I4)
m_nTempConsumers = (long) vTemp;
else
m_nTempConsumers = DEF_TEMP_CONS;
if (SUCCEEDED(pObj->Get(L"SlowDownProviders", 0, &vTemp, NULL, NULL)) &&
vTemp.vt == VT_BOOL)
m_bSlowDownProviders = (bool) vTemp;
else
m_bSlowDownProviders = DEF_SLOW_DOWN;
if (SUCCEEDED(pObj->Get(L"SlowDownProviders", 0, &vTemp, NULL, NULL)) &&
vTemp.vt == VT_BOOL)
m_bSlowDownProviders = (bool) vTemp;
else
m_bSlowDownProviders = DEF_SLOW_DOWN;
// Load the item's event generator.
IWbemClassObjectPtr pGenerator;
if (SUCCEEDED(hr = pObj->Get(L"EventGenerator", 0, &vTemp, NULL, NULL)) &&
SUCCEEDED(hr = g_essTest.GetDefNamespace()->GetObject(
V_BSTR(&vTemp),
WBEM_FLAG_RETURN_WBEM_COMPLETE,
NULL,
&pGenerator,
NULL)))
{
m_strGeneratorName = V_BSTR(&vTemp);
if (SUCCEEDED(pGenerator->Get(L"EventNamespace", 0, &vTemp, NULL, NULL)) &&
vTemp.vt == VT_BSTR)
{
if (FAILED(g_essTest.GetNamespace(V_BSTR(&vTemp), &m_pNamespace)))
return WBEM_E_FAILED;
}
else
m_pNamespace = g_essTest.GetDefNamespace();
if (SUCCEEDED(pGenerator->Get(L"Script", 0, &vTemp, NULL, NULL)) &&
vTemp.vt == VT_BSTR)
{
m_strRawScript = V_BSTR(&vTemp);
if (!CreateScriptResultsFile(L"1", m_strEventGenFile))
return WBEM_E_FAILED;
}
if (SUCCEEDED(pGenerator->Get(L"FullCompare", 0, &vTemp, NULL, NULL)) &&
vTemp.vt == VT_BOOL)
{
m_bFullCompare = (bool) vTemp;
}
if (SUCCEEDED(hr =
pGenerator->Get(L"CommandLine", 0, &vTemp, NULL, NULL)))
{
m_strCommandLine = V_BSTR(&vTemp);
if (m_strEventGenFile.length())
ReplaceString(m_strCommandLine, L"%ResultsFile%", m_strEventGenFile);
hr = InsertReplacementStrings(m_strCommandLine, pObj);
}
}
}
return hr;
}
void ChangeFileExt(LPWSTR szPath, LPCWSTR szNewExt)
{
WCHAR szOldPath[MAX_PATH],
szDrive[MAX_PATH],
szDir[MAX_PATH],
szName[MAX_PATH],
szExt[MAX_PATH];
wcscpy(szOldPath, szPath);
_wsplitpath(szPath, szDrive, szDir, szName, szExt);
_wmakepath(szPath, szDrive, szDir, szName, szNewExt);
// Make sure the file doesn't already exit.
DeleteFileW(szPath);
MoveFileW(szOldPath, szPath);
}
BOOL CWorkItem::CreateScriptResultsFile(LPCWSTR szRule, _bstr_t &strFileName)
{
_bstr_t strScriptContents = (LPWSTR) m_strRawScript;
WCHAR szScriptFile[MAX_PATH * 2] = L"",
szResultFile[MAX_PATH * 2] = L"";
ReplaceString(strScriptContents, L"%ScriptRule%", szRule);
GetTempFileNameW(L".", L"SRC", 0, szScriptFile);
GetTempFileNameW(L".", L"DST", 0, szResultFile);
ChangeFileExt(szScriptFile, L".js");
FILE *pFile = _wfopen(szScriptFile, L"w");
BOOL bRet = FALSE;
if (pFile)
{
fputs((LPSTR) strScriptContents, pFile);
bRet = TRUE;
fclose(pFile);
WCHAR szCmdLine[MAX_PATH * 3];
swprintf(
szCmdLine,
L"cmd /c \"cscript %s //Nologo %d > %s\"",
szScriptFile,
m_nEvents,
szResultFile);
STARTUPINFOW startinfo = { sizeof(startinfo) };
PROCESS_INFORMATION procinfo;
GetStartupInfoW(&startinfo);
// Get out base timestamp.
m_dwBaseTimestamp = GetTickCount();
if (CreateProcessW(
NULL,
szCmdLine,
NULL,
NULL,
FALSE,
0,
NULL,
NULL,
&startinfo,
&procinfo))
{
CloseHandle(procinfo.hThread);
WaitForSingleObject(procinfo.hProcess, INFINITE);
CloseHandle(procinfo.hProcess);
strFileName = szResultFile;
bRet = TRUE;
}
else
{
g_essTest.PrintError(
"Failed to create script results file '%S': error %d",
szResultFile,
GetLastError());
}
// Get rid of the source script file.
if (!g_essTest.KeepLogs())
DeleteFileW(szScriptFile);
}
else
{
g_essTest.PrintError(
"Failed to create script file '%S'.",
szScriptFile);
}
return bRet;
}
HRESULT CWorkItem::InitFilters()
{
IEnumWbemClassObject *pEnum = NULL;
WCHAR szQuery[512];
HRESULT hr;
IWbemClassObjectPtr pobjAssoc,
pobjFilter;
IWbemServices *pDefNamespace = g_essTest.GetDefNamespace();
if (FAILED(hr =
g_essTest.SpawnInstance(
L"MSFT_EssTestEventFilterToTestFilter",
&pobjAssoc)) ||
FAILED(hr =
g_essTest.SpawnInstance(
L"__EventFilter",
&pobjFilter)))
{
return hr;
}
_variant_t vTemp = L"WQL";
_bstr_t strName = (LPWSTR) m_strGeneratorName;
pobjFilter->Put(L"QueryLanguage", 0, &vTemp, 0);
pobjFilter->Put(L"ConditionLanguage", 0, &vTemp, 0);
EscapeQuotedString(strName);
swprintf(
szQuery,
L"select * from MSFT_EssTestFilter where "
L"EventGenerator=\"%s\"",
(LPWSTR) strName);
_bstr_t strWQL = L"WQL",
strQuery = szQuery;
hr =
pDefNamespace->ExecQuery(
strWQL,
strQuery,
WBEM_FLAG_FORWARD_ONLY,
NULL,
&pEnum);
if (SUCCEEDED(hr))
{
IWbemClassObjectPtr pObj;
DWORD nCount;
while(SUCCEEDED(hr = pEnum->Next(WBEM_INFINITE, 1, &pObj, &nCount)) &&
nCount > 0)
{
_variant_t vName(L"???");
_variant_t vBehavior((long) 0);
pObj->Get(L"Name", 0, &vName, NULL, NULL);
pObj->Get(L"Behavior", 0, &vBehavior, NULL, NULL);
if ((long) vBehavior != 0)
{
CWorkFilter *pFilter = new CWorkFilter;
HRESULT hr;
if (SUCCEEDED(hr = pFilter->Init(pObj, this)))
{
// Create an __EventFilter intance.
_variant_t vTemp;
vTemp = pFilter->m_strQuery;
pobjFilter->Put(L"Query", 0, &vTemp, 0);
vTemp = pFilter->m_strName;
pobjFilter->Put(L"Name", 0, &vTemp, 0);
pObj->Get(L"ConditionNamespace", 0, &vTemp, NULL, NULL);
pobjFilter->Put(L"ConditionNamespace", 0, &vTemp, 0);
pObj->Get(L"Condition", 0, &vTemp, NULL, NULL);
pobjFilter->Put(L"Condition", 0, &vTemp, 0);
hr = pDefNamespace->PutInstance(
pobjFilter, WBEM_FLAG_CREATE_OR_UPDATE, NULL, NULL);
if (SUCCEEDED(hr))
{
g_essTest.PrintStatus(
"Created __EventFilter=\"%S\"",
(BSTR) pFilter->m_strName);
}
else
{
g_essTest.PrintError(
"Failed to put __EventFilter '%S' for item '%S': 0x%X",
V_BSTR(&vTemp),
(BSTR) m_strName,
hr);
continue;
}
// Create a MSFT_EssTestEventFilterToTestFilter intance.
pobjFilter->Get(L"__RELPATH", 0, &vTemp, NULL, NULL);
pobjAssoc->Put(L"EventFilter", 0, &vTemp, 0);
pObj->Get(L"__RELPATH", 0, &vTemp, NULL, NULL);
pobjAssoc->Put(L"TestFilter", 0, &vTemp, 0);
hr = pDefNamespace->PutInstance(
pobjAssoc, WBEM_FLAG_CREATE_OR_UPDATE, NULL, NULL);
if (FAILED(hr))
{
g_essTest.PrintError(
"Failed to put MSFT_EssTestEventFilterToTestFilter '%S' for item '%S': 0x%X",
V_BSTR(&vTemp),
(BSTR) m_strName,
hr);
continue;
}
m_listFilters.push_back(pFilter);
// Keep a separate list of non-guarded filters for our
// temporary consumers.
if (pFilter->m_strCondition.length() == 0)
m_listNonGuardedFilters.push_back(pFilter);
g_essTest.PrintStatus(
"Loaded work filter '%S' for item '%S'.",
V_BSTR(&vName),
(BSTR) m_strName);
}
else
{
g_essTest.PrintError(
"Failed to init work filter '%S' for item '%S': 0x%X",
V_BSTR(&vName),
(BSTR) m_strName,
hr);
}
}
else
{
g_essTest.PrintStatus(
"Skipping disabled work filter '%S' for item '%S'.",
V_BSTR(&vName),
(BSTR) m_strName);
}
}
pEnum->Release();
}
else
{
g_essTest.PrintError(
"Failed to enumerate work filters for item '%S': 0x%X",
(BSTR) m_strName,
hr);
}
return hr;
}
HRESULT CWorkItem::InitConsumers()
{
// Build up the consumers.
HRESULT hr;
IWbemClassObjectPtr pConsumer;
WCHAR szDir[MAX_PATH * 2],
*pszLast;
GetModuleFileNameW(NULL, szDir, sizeof(szDir));
if ((pszLast = wcsrchr(szDir, '\\')) != NULL)
*(pszLast + 1) = 0;
else
*szDir = 0;
// Do the permanent consumers.
if (SUCCEEDED(hr =
g_essTest.SpawnInstance(L"MSFT_WmiMofConsumer", &pConsumer)))
{
IWbemServices *pNamespace = g_essTest.GetDefNamespace();
_variant_t vBlobs(true);
// Tell the consumer to save output as blobs instead of mofs.
pConsumer->Put(L"SaveAsBlobs", 0, &vBlobs, 0);
for (DWORD i = 0; i < m_nPermConsumers; i++)
{
WCHAR szName[100],
szFile[MAX_PATH * 2];
swprintf(szName, L"I%02d_PC%03d.bin", m_dwID, i);
wcscpy(szFile, szDir);
wcscat(szFile, szName);
// Get rid of any file with the same name.
DeleteFileW(szFile);
_variant_t vName = szName,
vFile = szFile;
pConsumer->Put(L"Name", 0, &vName, 0);
pConsumer->Put(L"MofFile", 0, &vFile, 0);
hr = pNamespace->PutInstance(
pConsumer, WBEM_FLAG_CREATE_OR_UPDATE, NULL, NULL);
if (SUCCEEDED(hr))
{
CPermConsumer *pConsumer = new CPermConsumer;
pConsumer->m_strName = szName;
pConsumer->m_strFile = szFile;
m_listPermConsumers.push_back(pConsumer);
g_essTest.PrintStatus(
"Created MSFT_WmiMofConsumer=\"%S\"",
szName);
}
else
{
g_essTest.PrintError(
"Failed to put MSFT_WmiMofConsumer=\"%S\" for item '%S': 0x%X",
V_BSTR(&vName),
(BSTR) m_strName,
hr);
}
}
}
// Do the temporary consumers.
for (DWORD i = 0; i < m_nTempConsumers; i++)
{
WCHAR szName[100],
szFile[MAX_PATH * 2];
swprintf(szName, L"I%02d_TC%03d.bin", m_dwID, i);
wcscpy(szFile, szDir);
wcscat(szFile, szName);
// Get rid of any file with the same name.
DeleteFileW(szFile);
CTempConsumer *pConsumer = new CTempConsumer;
pConsumer->m_strName = szName;
pConsumer->m_strFile = szFile;
m_listTempConsumers.push_back(pConsumer);
g_essTest.PrintStatus(
"Created temp consumer = \"%S\"",
szName);
}
return hr;
}
#define EXTRA_WAIT_TIME 7000
#define CYCLE_TIME 1000
void CWorkItem::AddFilterToAllConsumers(CWorkFilter *pFilter, DWORD dwTimestamp)
{
for (CPConsumerListIterator perm = m_listPermConsumers.begin();
perm != m_listPermConsumers.end();
perm++)
{
CPermConsumer *pPerm = *perm;
pPerm->AddFilter(pFilter, dwTimestamp);
}
}
void CWorkItem::RemoveFilterFromAllConsumers(CWorkFilter *pFilter, DWORD dwTimestamp)
{
for (CPConsumerListIterator perm = m_listPermConsumers.begin();
perm != m_listPermConsumers.end();
perm++)
{
CPermConsumer *pPerm = *perm;
pPerm->RemoveFilter(pFilter, dwTimestamp);
}
}
void CWorkItem::Run()
{
HRESULT hr;
if (FAILED(hr = InitFilters()))
{
g_essTest.PrintError(
"Unable to init filters: 0x%X", hr);
return;
}
if (FAILED(hr = InitConsumers()))
{
g_essTest.PrintError(
"Unable to init consumers: 0x%X", hr);
return;
}
// Add the full-time filters to the consumers.
for (CWorkFilterListIterator filter = m_listFilters.begin();
filter != m_listFilters.end();
filter++)
{
CWorkFilter *pFilter = *filter;
if (pFilter->m_type == FILTER_FULLTIME)
AddFilterToAllConsumers(pFilter, 0);
}
for (DWORD iTime = 0; iTime < m_nTimesToRepeat; iTime++)
{
g_essTest.PrintStatus(
"Work item '%S' execution #%d...", (BSTR) m_strName, iTime + 1);
// Reset our permanent consumers.
for (CPConsumerListIterator perm = m_listPermConsumers.begin();
perm != m_listPermConsumers.end();
perm++)
{
CPermConsumer *pPerm = *perm;
// Remove all filters except for the full-time ones.
pPerm->ResetFilterItems(TRUE);
}
// Start our temporary consumers.
int nFilters = m_listNonGuardedFilters.size();
for (int i = 0; i < m_listTempConsumers.size(); i++)
{
CTempConsumer *pTemp = m_listTempConsumers[i];
// Add a filter to the temporary consumer.
pTemp->SetFilter(m_listNonGuardedFilters[i % nFilters], 0);
// Start the temporary consumer.
pTemp->Start();
}
// Reset the on at/off at filters to waiting.
for (CWorkFilterListIterator filter = m_listFilters.begin();
filter != m_listFilters.end();
filter++)
{
CWorkFilter *pFilter = *filter;
if (pFilter->m_type == FILTER_ONAT_OFFAT)
pFilter->m_state = FILTER_WAITING_TO_RUN;
}
Sleep(3000);
// Launch the work item's command-line to generate the events.
STARTUPINFO startinfo = { sizeof(startinfo) };
PROCESS_INFORMATION procinfo;
GetStartupInfo(&startinfo);
// Get out base timestamp.
m_dwBaseTimestamp = GetTickCount();
if (CreateProcess(
NULL,
m_strCommandLine,
NULL,
NULL,
FALSE,
0,
NULL,
NULL,
&startinfo,
&procinfo))
{
CloseHandle(procinfo.hThread);
// Wait for a second (or until our event process is done), then do
// some work for the filters that come and go.
while (WaitForSingleObject(procinfo.hProcess, CYCLE_TIME) == WAIT_TIMEOUT)
CycleFilters();
CloseHandle(procinfo.hProcess);
// Wait a little to make sure all the events got through.
Sleep(EXTRA_WAIT_TIME);
g_essTest.LockOutput();
g_essTest.PrintResult(
"\n*** Work Item Results for '%S' (execution #%d) ***",
(BSTR) m_strName,
iTime + 1);
for (CPConsumerListIterator perm = m_listPermConsumers.begin();
perm != m_listPermConsumers.end();
perm++)
{
CPermConsumer *pPerm = *perm;
// Validate our results.
pPerm->ValidateResults();
}
for (CTConsumerListIterator temp = m_listTempConsumers.begin();
temp != m_listTempConsumers.end();
temp++)
{
CTempConsumer *pTemp = *temp;
// Validate our results.
pTemp->ValidateResults();
}
g_essTest.UnlockOutput();
}
else
{
g_essTest.PrintStatus(
"Work item '%S' failed to execute: %d\n"
" Command-line: %S",
(BSTR) m_strName,
GetLastError(),
(BSTR) m_strCommandLine);
}
}
}
#define random(x) (rand() % x)
#define NUM_CHANCES 10
void CWorkItem::CycleFilters()
{
DWORD dwTimestamp = GetTickCount(),
nElapsedSeconds = (dwTimestamp - m_dwBaseTimestamp) / 1000;
for (CWorkFilterListIterator filter = m_listFilters.begin();
filter != m_listFilters.end();
filter++)
{
CWorkFilter *pFilter = *filter;
if (pFilter->m_type == FILTER_ONAT_OFFAT)
{
if (pFilter->m_state == FILTER_WAITING_TO_RUN &&
pFilter->m_dwOnAt <= nElapsedSeconds)
{
pFilter->m_state = FILTER_RUNNING;
AddFilterToAllConsumers(pFilter, dwTimestamp);
}
else if (pFilter->m_state == FILTER_RUNNING &&
pFilter->m_dwOffAt <= nElapsedSeconds)
{
pFilter->m_state = FILTER_DONE;
RemoveFilterFromAllConsumers(pFilter, dwTimestamp);
}
}
else if (pFilter->m_type == FILTER_RANDOM)
{
for (CPConsumerListIterator perm = m_listPermConsumers.begin();
perm != m_listPermConsumers.end();
perm++)
{
CPermConsumer *pPerm = *perm;
DWORD dwAction = random(NUM_CHANCES);
if (dwAction == 0)
pPerm->AddFilter(pFilter, dwTimestamp);
else if (dwAction == 1)
pPerm->RemoveFilter(pFilter, dwTimestamp);
}
}
}
}
/////////////////////////////////////////////////////////////////////////////
// CConsumer
#define MAX_TRIES 30
CConsumer::~CConsumer()
{
if (!g_essTest.KeepLogs() && m_strFile.length())
DeleteFileW(m_strFile);
}
BOOL CConsumer::FileToObjs(CFlexArray &listEvents, IWbemServices *pNamespace)
{
FILE *pFile;
// Wait for the file to be readable.
for (int i = 0; i <= MAX_TRIES; i++)
{
pFile = _wfsopen(m_strFile, L"rb", _SH_DENYWR);
if (pFile)
break;
if (i < MAX_TRIES)
Sleep(1000);
else
{
g_essTest.PrintError(
"Unable to open results file '%S': %d",
(BSTR) m_strFile,
GetLastError());
return FALSE;
}
}
// Build an array of _IWmiObjects from the events the consumer
// received.
_bstr_t strClass = L"__EventFilter";
IWbemClassObject *pClass = NULL;
_IWmiObject *pObj = NULL;
HRESULT hr;
DWORD dwSize;
BYTE cBuffer[64000];
hr =
pNamespace->GetObject(
strClass,
0,
NULL,
&pClass,
NULL);
while(fread(&dwSize, 1, 4, pFile) == 4 &&
fread(cBuffer, 1, dwSize, pFile) == dwSize)
{
BSTR bstrObj = NULL;
LPVOID pMem = CoTaskMemAlloc(dwSize);
// Yes, I'm naughty and I know it!
hr = pClass->SpawnInstance(0, (IWbemClassObject**) &pObj);
memcpy(pMem, cBuffer, dwSize);
hr = pObj->SetObjectMemory(pMem, dwSize);
listEvents.Add(pObj);
}
pClass->Release();
// We don't need this file anymore.
fclose(pFile);
return TRUE;
}
BOOL CConsumer::ValidatePermFilter(CFlexArray &listEvents, CFilterItem &item)
{
_IWmiObject **ppEvents = (_IWmiObject**) listEvents.GetArrayPtr();
DWORD nEvents = listEvents.Size();
for (DWORD i = 0; i < nEvents; i++)
{
if (ppEvents[i] != NULL &&
item.m_table.FindInstance(
ppEvents[i], TRUE, item.m_pFilter->m_pWorkItem->m_bFullCompare))
{
ppEvents[i]->Release();
ppEvents[i] = NULL;
}
}
if (item.m_table.GetNumMatched() == item.m_table.GetSize())
{
g_essTest.PrintResult(
"SUCCESS: All events received for consumer '%S'<-->FTF '%S'.",
(BSTR) m_strName,
(BSTR) item.m_pFilter->m_strName);
}
else
{
g_essTest.PrintResult(
"FAILURE: The following events were not received for consumer '%S'<-->FTF'%S':",
(BSTR) m_strName,
(BSTR) item.m_pFilter->m_strName);
item.m_table.PrintUnmatchedObjMofs();
}
return TRUE;
}
BOOL CConsumer::ReportUnmatchedEvents(CFlexArray &listEvents, DWORD nMatched)
{
DWORD nEvents = listEvents.Size();
if (nMatched == nEvents)
{
/* This seems like kind of a meaningless message...
g_essTest.PrintResult(
"SUCCESS: All events received by '%S' matched to filters.",
(BSTR) m_strName);
*/
}
else
{
_IWmiObject **ppEvents = (_IWmiObject**) listEvents.GetArrayPtr();
g_essTest.PrintResult(
"FAILURE: The following events received by '%S' were not matched "
"to any filters:",
(BSTR) m_strName);
for (DWORD i = 0; i < nEvents; i++)
{
if (ppEvents[i] != NULL)
{
HRESULT hr;
BSTR bstrObj = NULL;
if (SUCCEEDED(hr = ppEvents[i]->GetObjectText(0, &bstrObj)))
{
g_essTest.PrintResult("%S", bstrObj);
SysFreeString(bstrObj);
}
else
g_essTest.PrintResult(
"\n// IWbemClassObject::GetObjectText failed : 0x%X\n", hr);
ppEvents[i]->Release();
}
}
}
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
// CPermConsumer
CPermConsumer::~CPermConsumer()
{
_bstr_t strPath;
_variant_t vPath;
HRESULT hr;
// Get rid of all bindings.
ResetFilterItems(FALSE);
GetPath(strPath);
vPath = strPath;
hr = g_essTest.GetDefNamespace()->DeleteInstance(
V_BSTR(&vPath), 0, NULL, NULL);
}
BOOL CPermConsumer::ValidateResults()
{
CFlexArray listEvents;
IWbemServices *pNamespace = (*m_listFilters.begin()).m_pFilter->
m_pWorkItem->m_pNamespace;
if (!FileToObjs(listEvents, pNamespace))
return FALSE;
_IWmiObject **ppEvents = (_IWmiObject**) listEvents.GetArrayPtr();
DWORD nEvents = listEvents.Size(),
nMatched = 0;
/////////////////////////////////////////////////////////////////////////
// Validation Step 1:
// See if the full-time consumers got all of their expected events.
for (CFilterItemListIterator filter = m_listFilters.begin();
filter != m_listFilters.end();
filter++)
{
CFilterItem &item = *filter;
if (item.m_pFilter->m_type == FILTER_FULLTIME)
{
ValidatePermFilter(listEvents, item);
nMatched += item.m_table.GetNumMatched();
}
}
/////////////////////////////////////////////////////////////////////////
// Validation Step 2:
// Check the non-full-time filters.
for (filter = m_listFilters.begin();
filter != m_listFilters.end();
filter++)
{
CFilterItem &item = *filter;
if (item.m_pFilter->m_type != FILTER_FULLTIME)
{
for (DWORD i = 0; i < nEvents; i++)
{
if (ppEvents[i] != NULL &&
item.m_table.FindInstance(
ppEvents[i], FALSE, item.m_pFilter->m_pWorkItem->m_bFullCompare))
{
ppEvents[i]->Release();
ppEvents[i] = NULL;
nMatched++;
}
}
g_essTest.PrintStatus(
"%d events received for consumer '%S'<-->PTF '%S'.",
item.m_table.GetNumMatched(),
(BSTR) m_strName,
(BSTR) item.m_pFilter->m_strName);
}
}
/////////////////////////////////////////////////////////////////////////
// Validation Step 3:
// Report any unmatched events left over as an error.
ReportUnmatchedEvents(listEvents, nMatched);
return TRUE;
}
void CPermConsumer::GetPath(_bstr_t &strPath)
{
WCHAR szPath[MAX_PATH * 2];
swprintf(szPath, L"MSFT_WmiMofConsumer=\"%s\"", (BSTR) m_strName);
strPath = szPath;
}
HRESULT CPermConsumer::GetBindingObj(CWorkFilter *pFilter, IWbemClassObject **ppBinding)
{
HRESULT hr;
if (SUCCEEDED(hr =
g_essTest.SpawnInstance(L"__FilterToConsumerBinding", ppBinding)))
{
_bstr_t strConsumerPath,
strFilterPath;
GetPath(strConsumerPath);
pFilter->GetPath(strFilterPath);
_variant_t vTemp;
vTemp = strConsumerPath;
hr = (*ppBinding)->Put(L"Consumer", 0, &vTemp, 0);
if (SUCCEEDED(hr))
{
vTemp = strFilterPath;
hr = (*ppBinding)->Put(L"Filter", 0, &vTemp, 0);
vTemp = true;
hr = (*ppBinding)->Put(L"SlowDownProviders", 0, &vTemp, 0);
}
}
return hr;
}
void CPermConsumer::AddFilter(CWorkFilter *pFilter, DWORD dwTimestamp)
{
HRESULT hr;
IWbemClassObjectPtr pBinding;
// See if we already have an active filter of this type. We can
// tell by looking in our list for an item where m_pFilter ==
// pFilter && m_dwEnd == 0.
for (CFilterItemListIterator filter = m_listFilters.begin();
filter != m_listFilters.end();
filter++)
{
CFilterItem &item = *filter;
if (item.m_pFilter == pFilter && item.m_dwEnd == 0)
return;
}
if (SUCCEEDED(hr =
GetBindingObj(pFilter, &pBinding)))
{
_variant_t vPath;
hr = g_essTest.GetDefNamespace()->PutInstance(
pBinding, WBEM_FLAG_CREATE_OR_UPDATE, NULL, NULL);
pBinding->Get(L"__RELPATH", 0, &vPath, NULL, NULL);
if (SUCCEEDED(hr))
{
CFilterItem item(dwTimestamp);
item.m_dwBegin = dwTimestamp;
item.m_pFilter = pFilter;
m_listFilters.push_back(item);
// Make the newly inserted item share the filter's table.
CFilterItem &itemNew = m_listFilters.back();
itemNew.m_table = pFilter->m_table;
g_essTest.PrintStatus(
"Created %S",
V_BSTR(&vPath));
}
else
{
g_essTest.PrintError(
"Failed to put '%S': 0x%X",
V_BSTR(&vPath),
hr);
}
}
else
{
g_essTest.PrintError(
"Failed to get instance of __FilterToConsumerBinding: 0x%X",
hr);
}
}
HRESULT CPermConsumer::RemoveBinding(CWorkFilter *pFilter)
{
IWbemClassObjectPtr pBinding;
HRESULT hr;
if (SUCCEEDED(hr =
GetBindingObj(pFilter, &pBinding)))
{
_variant_t vPath;
pBinding->Get(L"__RELPATH", 0, &vPath, NULL, NULL);
hr = g_essTest.GetDefNamespace()->DeleteInstance(
V_BSTR(&vPath), 0, NULL, NULL);
if (FAILED(hr))
{
g_essTest.PrintError(
"Failed to delete '%S': 0x%X",
V_BSTR(&vPath),
hr);
}
}
else
{
g_essTest.PrintError(
"Failed to get instance of __FilterToConsumerBinding: 0x%X",
hr);
}
return hr;
}
void CPermConsumer::RemoveFilter(CWorkFilter *pFilter, DWORD dwTimestamp)
{
// See if we have an active filter of this type. If not, get out.
for (CFilterItemListIterator filter = m_listFilters.begin();
filter != m_listFilters.end();
filter++)
{
CFilterItem &item = *filter;
if (item.m_pFilter == pFilter && item.m_dwEnd == 0)
break;
}
if (filter == m_listFilters.end())
return;
(*filter).m_dwEnd = dwTimestamp;
RemoveBinding(pFilter);
}
void CPermConsumer::ResetFilterItems(BOOL bKeepFulltime)
{
// See if we have an active filter of this type. If not, get out.
for (CFilterItemListIterator filter = m_listFilters.begin();
filter != m_listFilters.end();
)
{
CFilterItem &item = *filter;
if (bKeepFulltime && item.m_pFilter->m_type == FILTER_FULLTIME)
{
filter++;
continue;
}
if (item.m_dwEnd == 0)
{
RemoveBinding(item.m_pFilter);
filter = m_listFilters.erase(filter);
}
else
filter++;
}
}
/////////////////////////////////////////////////////////////////////////////
// CTempConsumer
CTempConsumer::CTempConsumer() :
m_hProcess(NULL),
m_itemFilter(0)
{
}
CTempConsumer::~CTempConsumer()
{
if (m_hProcess)
CloseHandle(m_hProcess);
}
#define MAX_TEMP_WAIT 30000
BOOL CTempConsumer::ValidateResults()
{
// Wait for the file to be readable.
DWORD dwWait = WaitForSingleObject(m_hProcess, MAX_TEMP_WAIT);
if (dwWait == WAIT_TIMEOUT)
{
g_essTest.PrintError(
"Temporary subscriber '%S' never terminated.\n",
(BSTR) m_strName);
return FALSE;
}
CFlexArray listEvents;
IWbemServices *pNamespace;
pNamespace = m_itemFilter.m_pFilter->m_pWorkItem->m_pNamespace;
if (!FileToObjs(listEvents, pNamespace))
return FALSE;
_IWmiObject **ppEvents = (_IWmiObject**) listEvents.GetArrayPtr();
DWORD nEvents = listEvents.Size(),
nMatched = 0;
/////////////////////////////////////////////////////////////////////////
// Validation Step 1:
// See if the full-time consumer got all of their expected events.
ValidatePermFilter(listEvents, m_itemFilter);
nMatched += m_itemFilter.m_table.GetNumMatched();
/////////////////////////////////////////////////////////////////////////
// Validation Step 2:
// Report any unmatched events left over as an error.
ReportUnmatchedEvents(listEvents, nMatched);
return TRUE;
}
void CTempConsumer::SetFilter(CWorkFilter *pFilter, DWORD dwTimestamp)
{
m_itemFilter.m_dwBegin = dwTimestamp;
m_itemFilter.m_pFilter = pFilter;
m_itemFilter.m_table = pFilter->m_table;
g_essTest.PrintStatus(
"Created temp consumer, query = \"%S\"",
(BSTR) pFilter->m_strQuery);
}
void CTempConsumer::Start()
{
WCHAR *szCmd = new WCHAR[wcslen(m_itemFilter.m_pFilter->m_strQuery) +
wcslen(m_strFile) + 100];
swprintf(
szCmd,
L"EventDmp /Nroot\\cimv2 /T30 \"/B%s\" \"%s\"",
(BSTR) m_strFile,
(BSTR) m_itemFilter.m_pFilter->m_strQuery);
// Launch the work item's command-line to generate the events.
STARTUPINFOW startinfo = { sizeof(startinfo) };
PROCESS_INFORMATION procinfo;
GetStartupInfoW(&startinfo);
if (CreateProcessW(
NULL,
szCmd,
NULL,
NULL,
FALSE,
0,
NULL,
NULL,
&startinfo,
&procinfo))
{
CloseHandle(procinfo.hThread);
m_hProcess = procinfo.hProcess;
g_essTest.PrintStatus(
"Temp consumer '%S' started.\n"
" Command-line: %S",
(BSTR) m_strName,
szCmd);
}
else
{
g_essTest.PrintError(
"Temp consumer '%S' failed to execute: %d\n"
" Command-line: %S",
(BSTR) m_strName,
GetLastError(),
szCmd);
}
delete [] szCmd;
}
/////////////////////////////////////////////////////////////////////////////
// CWorkFilter
CWorkFilter::~CWorkFilter()
{
_bstr_t strPath;
_variant_t vPath;
HRESULT hr;
GetPath(strPath);
vPath = strPath;
// Kill everything referencing our path.
g_essTest.DeleteReferences(strPath);
hr = g_essTest.GetDefNamespace()->DeleteInstance(
V_BSTR(&vPath), 0, NULL, NULL);
}
void CWorkFilter::GetPath(_bstr_t &strPath)
{
WCHAR szPath[MAX_PATH * 2];
swprintf(szPath, L"__EventFilter=\"%s\"", (BSTR) m_strName);
strPath = szPath;
}
void CWorkFilter::GetAssocPath(_bstr_t &strPath)
{
WCHAR szPath[MAX_PATH * 2];
swprintf(szPath, L"__EventFilter=\"%s\"", (BSTR) m_strName);
strPath = szPath;
}
HRESULT CWorkFilter::Init(IWbemClassObject *pTestFilter, CWorkItem *pItem)
{
HRESULT hr;
_variant_t vTemp;
m_pWorkItem = pItem;
// Load the work item's properties.
if (SUCCEEDED(hr = pTestFilter->Get(L"Name", 0, &vTemp, NULL, NULL)))
{
m_strName = V_BSTR(&vTemp);
if (SUCCEEDED(hr = pTestFilter->Get(L"Query", 0, &vTemp, NULL, NULL)) &&
vTemp.vt == VT_BSTR)
m_strQuery = V_BSTR(&vTemp);
else
return hr;
if (SUCCEEDED(hr = pTestFilter->Get(L"Condition", 0, &vTemp, NULL, NULL)) &&
vTemp.vt == VT_BSTR)
m_strCondition = V_BSTR(&vTemp);
if (SUCCEEDED(hr = pTestFilter->Get(L"ConditionNamespace", 0, &vTemp, NULL, NULL)) &&
vTemp.vt == VT_BSTR)
m_strConditionNamespace = V_BSTR(&vTemp);
if (SUCCEEDED(hr = pTestFilter->Get(L"Behavior", 0, &vTemp, NULL, NULL)) &&
vTemp.vt == VT_I4)
{
m_type = (FILTER_BEHAVIOR) (long) vTemp;
if (m_type > FILTER_RANDOM)
m_type = FILTER_RANDOM;
if (m_type == FILTER_ONAT_OFFAT)
{
if (SUCCEEDED(hr = pTestFilter->Get(L"OnAt", 0, &vTemp, NULL, NULL)) &&
vTemp.vt == VT_I4)
m_dwOnAt = (long) vTemp;
if (SUCCEEDED(hr = pTestFilter->Get(L"OffAt", 0, &vTemp, NULL, NULL)) &&
vTemp.vt == VT_I4)
m_dwOffAt = (long) vTemp;
}
}
else
return hr;
if (SUCCEEDED(hr = pTestFilter->Get(L"ScriptRule", 0, &vTemp, NULL, NULL)) &&
vTemp.vt == VT_BSTR)
{
_bstr_t strFileName;
if (pItem->CreateScriptResultsFile(V_BSTR(&vTemp), strFileName))
{
BOOL bRet = m_table.BuildFromMofFile(
pItem->m_pNamespace,
strFileName);
if (!bRet)
{
g_essTest.PrintError(
"Unable to create instance table from rule '%S'.",
V_BSTR(&vTemp));
hr = WBEM_E_FAILED;
}
if (!g_essTest.KeepLogs() && strFileName.length())
DeleteFileW(strFileName);
}
}
else
return hr;
}
return hr;
}
/////////////////////////////////////////////////////////////////////////////
// Utility functions
void ReplaceString(_bstr_t &strSrc, LPCWSTR szFind, LPCWSTR szReplace)
{
_bstr_t strTemp = (LPWSTR) strSrc;
LPWSTR szFound = wcsstr((LPWSTR) strTemp, szFind);
if (szFound)
{
*szFound = 0;
szFound += wcslen(szFind);
strSrc = (LPWSTR) strTemp;
strSrc += szReplace;
strSrc += szFound;
}
}
HRESULT InsertReplacementStrings(_bstr_t &str, IWbemClassObject *pObj)
{
HRESULT hr = S_OK;
LPWSTR szFirst,
szSecond;
do
{
_bstr_t strTemp = (LPWSTR) str;
szFirst = wcschr((LPWSTR) strTemp, '%');
if (szFirst)
{
szSecond = wcschr(szFirst + 1, '%');
if (szSecond)
{
*szFirst = 0;
*szSecond = 0;
_variant_t vValue;
WCHAR szValue[512];
CIMTYPE type;
if (SUCCEEDED(hr = pObj->Get(szFirst + 1, 0, &vValue, &type, NULL)))
{
if (vValue.vt == VT_BSTR)
wcscpy(szValue, V_BSTR(&vValue));
else if (type == CIM_UINT32)
swprintf(szValue, L"%u", (long) vValue);
else if (type == CIM_SINT32)
swprintf(szValue, L"%d", (long) vValue);
else
// TODO: Do we need more types than this?
*szValue = 0;
str = (LPWSTR) strTemp;
str += szValue;
str += szSecond + 1;
}
}
}
} while (szFirst && szSecond && SUCCEEDED(hr));
return hr;
}
void EscapeQuotedString(_bstr_t &str)
{
WCHAR *pszTemp = (WCHAR*) malloc(str.length() * 2 * sizeof(WCHAR));
LPWSTR szSrc,
szDest = pszTemp;
for (szSrc = str; *szSrc; szSrc++)
{
switch(*szSrc)
{
case '\\':
case '\"':
*szDest = '\\';
szDest++;
break;
}
*szDest = *szSrc;
szDest++;
}
*szDest = 0;
str = pszTemp;
free(pszTemp);
}