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

1126 lines
29 KiB
C++

//******************************************************************************
//
// Copyright (c) 1999-2000, Microsoft Corporation, All rights reserved
//
//*****************************************************************************
#include "precomp.h"
#include <stdio.h>
#include <wbemcomn.h>
#include <ql.h>
#include <nsrep.h>
#include <monitor.h>
CMonitor::CMonitor()
: CGuardable(false),
m_CreationSink(this), m_DeletionSink(this), m_DataSink(this),
m_ModificationInSink(this), m_ModificationOutSink(this),
m_lRef(0), m_pNamespace(NULL), m_wszDataQuery(NULL), m_pCallback(NULL),
m_wszCreationEvent(NULL), m_wszDeletionEvent(NULL),
m_wszModificationInEvent(NULL), m_wszModificationOutEvent(NULL),
m_bFirstPollDone(FALSE)
{
}
CMonitor::~CMonitor()
{
if(m_lRef != 0)
{
ERRORTRACE((LOG_ESS, "Destroying monitor '%S' with non-0 ref-count: %d",
m_wszDataQuery, m_lRef));
}
if(m_pNamespace)
m_pNamespace->Release();
if(m_pCallback)
m_pCallback->Release();
delete [] m_wszDataQuery;
delete [] m_wszCreationEvent;
delete [] m_wszDeletionEvent;
delete [] m_wszModificationInEvent;
delete [] m_wszModificationOutEvent;
}
ULONG CMonitor::AddRef()
{
return InterlockedIncrement(&m_lRef);
}
ULONG CMonitor::Release()
{
// CMonitor is not controlled by its ref-count --- it is explicitely
// deleted by its parent.
return InterlockedDecrement(&m_lRef);
}
HRESULT CMonitor::Construct(CEssNamespace* pNamespace,
CMonitorCallback* pCallback, LPCWSTR wszQuery)
{
HRESULT hres;
//
// Parse the query
//
CTextLexSource src(wszQuery);
QL1_Parser parser(&src);
QL_LEVEL_1_RPN_EXPRESSION* pExp = NULL;
int nRes = parser.Parse(&pExp);
if (nRes)
{
ERRORTRACE((LOG_ESS, "Unable to parse data monitor query '%S'\n",
wszQuery));
return WBEM_E_UNPARSABLE_QUERY;
}
CDeleteMe<QL_LEVEL_1_RPN_EXPRESSION> dm(pExp);
m_bWithin = !pExp->Tolerance.m_bExact;
if(m_bWithin)
{
m_dwMsInterval = (DWORD)(pExp->Tolerance.m_fTolerance * 1000);
}
//
// Construct the tree for the membership test
//
CContextMetaData Meta(new CEssMetaData(pNamespace), GetCurrentEssContext());
hres = m_MembershipTest.CreateFromQuery(&Meta, pExp, 0, 0x7FFFFFFF);
if(FAILED(hres))
{
ERRORTRACE((LOG_ESS, "Unable to construct a tree from the data "
"monitor query '%S': 0x%X\n", wszQuery, hres));
return WBEM_E_UNPARSABLE_QUERY;
}
//
// Construct event queries we could issue to implement the monitor without
// polling
//
hres = ConstructWatchQueries(pExp, &m_wszCreationEvent,
&m_wszDeletionEvent, &m_wszModificationInEvent,
&m_wszModificationOutEvent);
if(FAILED(hres))
{
ERRORTRACE((LOG_ESS, "Unable to construct a watch query from "
"'%S': 0x%x\n", wszQuery, hres));
return hres;
}
m_pNamespace = pNamespace;
m_pNamespace->AddRef();
m_pCallback = pCallback;
if(m_pCallback)
m_pCallback->AddRef();
//
// Remove the tolerance clause from the data query, in case we need to poll
//
m_wszDataQuery = pExp->GetText();
return WBEM_S_NO_ERROR;
}
HRESULT CMonitor::ConstructWatchQueries(QL_LEVEL_1_RPN_EXPRESSION* pDataQ,
LPWSTR* pwszCreationEvent,
LPWSTR* pwszDeletionEvent,
LPWSTR* pwszModificationInEvent,
LPWSTR* pwszModificationOutEvent)
{
//
// BUGBUG: could do real analysis to make things faster
//
LPCWSTR wszTargetClassName = pDataQ->bsClassName;
*pwszCreationEvent = NULL;
*pwszDeletionEvent = NULL;
*pwszModificationInEvent = NULL;
*pwszModificationOutEvent = NULL;
*pwszCreationEvent = new WCHAR[wcslen(wszTargetClassName) + 200];
*pwszDeletionEvent = new WCHAR[wcslen(wszTargetClassName) + 200];
*pwszModificationInEvent = new WCHAR[wcslen(wszTargetClassName) + 200];
*pwszModificationOutEvent = new WCHAR[wcslen(wszTargetClassName) + 200];
if(*pwszCreationEvent == NULL || *pwszDeletionEvent == NULL ||
*pwszModificationInEvent == NULL || *pwszModificationOutEvent == NULL)
{
delete *pwszCreationEvent;
delete *pwszDeletionEvent;
delete *pwszModificationInEvent;
delete *pwszModificationOutEvent;
return WBEM_E_OUT_OF_MEMORY;
}
swprintf(*pwszCreationEvent, L"select * from __InstanceCreationEvent where "
L"TargetInstance isa \"%s\"", wszTargetClassName);
swprintf(*pwszDeletionEvent, L"select * from __InstanceDeletionEvent where "
L"TargetInstance isa \"%s\"", wszTargetClassName);
swprintf(*pwszModificationInEvent,
L"select * from __InstanceModificationEvent where "
L"TargetInstance isa \"%s\"", wszTargetClassName);
swprintf(*pwszModificationOutEvent,
L"select * from __InstanceModificationEvent where "
L"TargetInstance isa \"%s\"", wszTargetClassName);
return WBEM_S_NO_ERROR;
}
HRESULT CMonitor::ActivateByGuard()
{
return WBEM_E_CRITICAL_ERROR;
}
HRESULT CMonitor::DeactivateByGuard()
{
return WBEM_E_CRITICAL_ERROR;
}
HRESULT CMonitor::Start(IWbemContext* pContext)
{
HRESULT hres;
//
// First, we'll attempt to implement it without polling --- using events
//
hres = ImplementUsingEvents(pContext);
if(FAILED(hres))
{
// Serious error that will prevent polling from working as well!
return hres;
}
else if(hres == WBEM_S_NO_ERROR)
{
// Success of event implementation
m_bUsingEvents = true;
return hres;
}
// WBEM_S_FALSE means: cannot activate using events, use polling
//
// Whether an error or normal failure occurred, attempt to activate using
// polling now.
//
hres = ImplementUsingPolling(pContext);
m_bUsingEvents = false;
return hres;
}
HRESULT CMonitor::Stop(IWbemContext* pContext)
{
//
// Stop it the way it was started
//
HRESULT hres;
if(m_bUsingEvents)
hres = StopUsingEvents(pContext);
else
hres = StopUsingPolling(pContext);
//
// Notify our clients that we are stopping
//
DWORD dwCount;
{
CInCritSec ics(&m_cs);
dwCount = m_map.size();
}
FireStop(dwCount);
return hres;
}
HRESULT CMonitor::ImplementUsingEvents(IWbemContext* pContext)
{
HRESULT hres;
// BUGBUG: propagate security context
//
// Remember that the data query is still outstanding and therefore
// extra race-condition book-keeping is still necessary
//
m_bDataDone = false;
//
// Subscribe to all the event queries we have stashed. It is assumed
// that the namespace is locked at this point.
//
hres = m_pNamespace->InternalRegisterNotificationSink(L"WQL",
m_wszCreationEvent,
0, WMIMSG_FLAG_QOS_EXPRESS, pContext,
&m_CreationSink, true, NULL );
if(SUCCEEDED(hres))
{
hres = m_pNamespace->InternalRegisterNotificationSink(L"WQL",
m_wszDeletionEvent,
0, WMIMSG_FLAG_QOS_EXPRESS, pContext,
&m_DeletionSink, true, NULL );
if(SUCCEEDED(hres))
{
hres = m_pNamespace->InternalRegisterNotificationSink(L"WQL",
m_wszModificationInEvent,
0, WMIMSG_FLAG_QOS_EXPRESS, pContext,
&m_ModificationInSink, true, NULL );
if(SUCCEEDED(hres))
{
hres = m_pNamespace->InternalRegisterNotificationSink(L"WQL",
m_wszModificationOutEvent,
0, WMIMSG_FLAG_QOS_EXPRESS, pContext,
&m_ModificationOutSink, true, NULL );
}
}
}
if(FAILED(hres))
{
UnregisterAll();
if(hres == WBEMESS_E_REGISTRATION_TOO_PRECISE)
{
//
// There are no event providers to survice all of these requests.
// That's OK --- it just means that we need to use polling to do
// this monitor.
//
return WBEM_S_FALSE;
}
else
{
ERRORTRACE((LOG_ESS, "Monitor '%S' encountered error 0x%X trying "
"to activate its event queries\n", m_wszDataQuery, hres));
return WBEM_S_FALSE;
}
}
//
// Now that we are subscribed for events, issue the data query
//
hres = m_pNamespace->ExecQuery(m_wszDataQuery, 0, &m_DataSink);
if(FAILED(hres))
{
ERRORTRACE((LOG_ESS, "Monitor '%S' encountered error 0x%X issuing its "
"initializing data query\n", m_wszDataQuery, hres));
return hres;
}
return WBEM_S_NO_ERROR;
}
HRESULT CMonitor::StopUsingEvents(IWbemContext* pContext)
{
return UnregisterAll();
}
HRESULT CMonitor::UnregisterAll()
{
//
// Cancel all queries
//
m_pNamespace->RemoveNotificationSink(&m_CreationSink);
m_pNamespace->RemoveNotificationSink(&m_DeletionSink);
m_pNamespace->RemoveNotificationSink(&m_ModificationInSink);
m_pNamespace->RemoveNotificationSink(&m_ModificationOutSink);
return WBEM_S_NO_ERROR;
}
HRESULT CMonitor::ImplementUsingPolling(IWbemContext* pContext)
{
HRESULT hres;
//
// As usual, polling is only possible if a WITHIN clause is specified
//
if(!m_bWithin)
return WBEMESS_E_REGISTRATION_TOO_PRECISE;
//
// Basically, we will keep issuing our data query every m_dwMsInterval
// seconds and issue events if needed.
//
// Construct the timer instruction that will do that
//
m_pInst = new CMonitorInstruction(m_pNamespace, this);
if(m_pInst == NULL)
return WBEM_E_OUT_OF_MEMORY;
m_pInst->AddRef();
hres = m_pInst->Initialize(L"WQL", m_wszDataQuery, m_dwMsInterval);
if (SUCCEEDED(hres))
{
hres =
m_pNamespace->GetTimerGenerator().Set(
m_pInst,
CWbemTime::GetZero());
}
if (FAILED(hres))
{
m_pInst->Release();
return hres;
}
return hres;
}
HRESULT CMonitor::StopUsingPolling(IWbemContext* pContext)
{
//
// Cancel the timer instruction
//
CIdentityTest Test(m_pInst);
((CTimerGenerator&)m_pNamespace->GetTimerGenerator()).Remove(&Test);
m_pInst->Release();
m_pInst = NULL;
return S_OK;
}
// This function is called on both creation and mod-in events. There appear
// to be no differences between the two.
HRESULT CMonitor::ProcessPossibleAdd(_IWmiObject* pObj, bool bEvent)
{
HRESULT hres;
//
// First, we need to run the object through the membership test, if it
// came from an event --- no need to do that for a poll
//
if(bEvent)
{
CSortedArray aTrues;
hres = m_MembershipTest.Evaluate(pObj, aTrues);
if(FAILED(hres))
{
ERRORTRACE((LOG_ESS, "Unable to verify set membership for incoming "
"object in monitor '%S': 0x%X\n", m_wszDataQuery));
return hres;
}
if(aTrues.Size() == 0)
{
//
// Not in the set --- this can happen because our event
// registrations
// might be a bit broader that we'd want them to be. Later on, we
// might want to count these false hits and if we get too many of
// them, perhaps switch to polling...
//
return WBEM_S_FALSE;
}
}
//
// Get its path
//
VARIANT v;
VariantInit(&v);
hres = pObj->Get(L"__RELPATH", 0, &v, NULL, NULL);
if(FAILED(hres) || V_VT(&v) != VT_BSTR)
return WBEM_E_CRITICAL_ERROR;
CClearMe cm(&v);
//
// Determine if firing is necessary
//
bool bFire;
DWORD dwObjectCount;
{
CInCritSec ics(&m_cs);
//
// See if we already have it
//
TIterator it = m_map.find(V_BSTR(&v));
if(it == m_map.end() || !it->second)
{
// it is either not there, or thre with FALSE as the presence
// indicator --- in either case, it's not thought to be in the set
//
// There is one test remaining --- if this is a data-add, we must
// make sure that we have not heard of this object before, for if
// we have, we must ignore this info --- events always override.
//
if(!bEvent &&
m_mapHeard.find(V_BSTR(&v)) != m_mapHeard.end())
{
bFire = false;
}
else
{
bFire = true;
m_map[V_BSTR(&v)] = true;
dwObjectCount = m_map.size();
if(!m_bDataDone)
m_mapHeard[V_BSTR(&v)] = true;
}
}
else
{
// It's already there
bFire = false;
}
}
if(bFire)
FireAssert(pObj, V_BSTR(&v), bEvent, dwObjectCount);
return WBEM_S_NO_ERROR;
}
HRESULT CMonitor::ProcessModOut(_IWmiObject* pObj, bool bEvent)
{
HRESULT hres;
//
// First, we need to make sure that the object has really been modified
// out of the set --- need to test that it's no longer in the set
//
CSortedArray aTrues;
hres = m_MembershipTest.Evaluate(pObj, aTrues);
if(FAILED(hres))
{
ERRORTRACE((LOG_ESS, "Unable to verify set membership for outgoing "
"object in monitor '%S': 0x%X\n", m_wszDataQuery));
return hres;
}
if(aTrues.Size() != 0)
{
//
// The object is still in the set --- false positive!
// This can happen because our event registrations
// might be a bit broader that we'd want them to be. Later on, we
// might want to count these false hits and if we get too many of them,
// perhaps switch to polling...
//
//
return WBEM_S_FALSE;
}
//
// The object really has moved out of the set. As long as it is currently
// listed as 'in', an event should be raised
//
return ProcessPossibleRemove(pObj, bEvent);
}
HRESULT CMonitor::ProcessDelete(_IWmiObject* pObj, bool bEvent)
{
HRESULT hres;
//
// As long as it is currently listed as 'in', an event should be raised
//
return ProcessPossibleRemove(pObj, bEvent);
}
HRESULT CMonitor::ProcessPossibleRemove(_IWmiObject* pObj, bool bEvent)
{
HRESULT hres;
//
// Get its path
//
VARIANT v;
VariantInit(&v);
hres = pObj->Get(L"__RELPATH", 0, &v, NULL, NULL);
if(FAILED(hres) || V_VT(&v) != VT_BSTR)
return WBEM_E_CRITICAL_ERROR;
CClearMe cm(&v);
//
// Determine if firing is necessary
//
BOOL bFire;
DWORD dwLeft;
{
CInCritSec ics(&m_cs);
//
// If we are not out of the data query yet, record the fact that
// we have seen this instance, since we must ignore any data object
// that is overriden by an event
//
if(!m_bDataDone)
m_mapHeard[V_BSTR(&v)] = true;
//
// See if we have it
//
TIterator it = m_map.find(V_BSTR(&v));
if(it == m_map.end())
{
// It's not there --- just ignore
bFire = false;
}
else
{
//
// There: remove and fire
//
m_map.erase(it);
bFire = true;
dwLeft = m_map.size();
}
}
if(bFire)
FireRetract(pObj, V_BSTR(&v), bEvent, dwLeft);
return WBEM_S_NO_ERROR;
}
HRESULT CMonitor::ProcessDataDone(HRESULT hresData, IWbemClassObject* pError)
{
DWORD dwCount;
{
CInCritSec ics(&m_cs);
dwCount = m_map.size();
m_bDataDone = true;
m_mapHeard.clear();
}
if(FAILED(hresData))
{
//
// Monitor data execution failed. We need to alert our clients to this
// fact, and schedule reinitialization.
//
FireError(hresData, pError);
// BUGBUG: Need to reinitialize!
}
else
{
FireReady(dwCount);
}
return WBEM_S_NO_ERROR;
}
HRESULT CMonitor::FireAssert(_IWmiObject* pObj, LPCWSTR wszPath, bool bEvent,
DWORD dwTotalItems)
{
CMonitorCallback* pCallback = GetCallback();
CTemplateReleaseMe<CMonitorCallback> rm1(pCallback);
if(pCallback)
return pCallback->Assert(pObj, wszPath, bEvent, dwTotalItems);
else
return WBEM_S_FALSE;
}
HRESULT CMonitor::FireRetract(_IWmiObject* pObj, LPCWSTR wszPath, bool bEvent,
DWORD dwTotalItems)
{
CMonitorCallback* pCallback = GetCallback();
CTemplateReleaseMe<CMonitorCallback> rm1(pCallback);
if(pCallback)
return pCallback->Retract(pObj, wszPath, bEvent, dwTotalItems);
else
return WBEM_S_FALSE;
}
HRESULT CMonitor::FireReady(DWORD dwTotalItems)
{
CMonitorCallback* pCallback = GetCallback();
CTemplateReleaseMe<CMonitorCallback> rm1(pCallback);
if(pCallback)
return pCallback->GoingUp(dwTotalItems);
else
return WBEM_S_FALSE;
}
HRESULT CMonitor::FireStop(DWORD dwTotalItems)
{
CMonitorCallback* pCallback = GetCallback();
CTemplateReleaseMe<CMonitorCallback> rm1(pCallback);
if(pCallback)
return pCallback->GoingDown(dwTotalItems);
else
return WBEM_S_FALSE;
}
HRESULT CMonitor::FireError(HRESULT hresError, IWbemClassObject* pErrorObj)
{
CMonitorCallback* pCallback = GetCallback();
CTemplateReleaseMe<CMonitorCallback> rm1(pCallback);
if(pCallback)
return pCallback->Error(hresError, pErrorObj);
else
return WBEM_S_FALSE;
}
RELEASE_ME CMonitorCallback* CMonitor::GetCallback()
{
CInCritSec ics(&m_cs);
if(m_pCallback)
m_pCallback->AddRef();
return m_pCallback;
}
HRESULT CMonitor::CCreationSink::Indicate(long lNumEvents,
IWbemEvent** apEvents,
CEventContext* pContext)
{
HRESULT hres;
for(long i = 0; i < lNumEvents; i++)
{
//
// Extract its TargetInstance and add it
//
VARIANT v;
hres = apEvents[i]->Get(L"TargetInstance", 0, &v, NULL, NULL);
if(FAILED(hres) || V_VT(&v) != VT_UNKNOWN)
{
ERRORTRACE((LOG_ESS, "Invalid instance creation event without "
"TargetInstance recieved by monitor '%S'\n",
m_pOuter->m_wszDataQuery));
continue;
}
CClearMe cm(&v);
_IWmiObject* pObj;
hres = V_UNKNOWN(&v)->QueryInterface(IID__IWmiObject, (void**)&pObj);
CReleaseMe rm(pObj);
hres = m_pOuter->ProcessPossibleAdd(pObj, true);
}
return WBEM_S_NO_ERROR;
}
HRESULT CMonitor::CModificationInSink::Indicate(long lNumEvents,
IWbemEvent** apEvents,
CEventContext* pContext)
{
HRESULT hres;
for(long i = 0; i < lNumEvents; i++)
{
//
// Extract its TargetInstance and add it
//
VARIANT v;
hres = apEvents[i]->Get(L"TargetInstance", 0, &v, NULL, NULL);
if(FAILED(hres) || V_VT(&v) != VT_UNKNOWN)
{
ERRORTRACE((LOG_ESS, "Invalid instance creation event without "
"TargetInstance recieved by monitor '%S'\n",
m_pOuter->m_wszDataQuery));
continue;
}
CClearMe cm(&v);
_IWmiObject* pObj;
hres = V_UNKNOWN(&v)->QueryInterface(IID__IWmiObject, (void**)&pObj);
CReleaseMe rm(pObj);
hres = m_pOuter->ProcessPossibleAdd(pObj, true);
}
return WBEM_S_NO_ERROR;
}
HRESULT CMonitor::CDeletionSink::Indicate(long lNumEvents,
IWbemEvent** apEvents,
CEventContext* pContext)
{
HRESULT hres;
for(long i = 0; i < lNumEvents; i++)
{
//
// Extract its TargetInstance and remove it
//
VARIANT v;
hres = apEvents[i]->Get(L"TargetInstance", 0, &v, NULL, NULL);
if(FAILED(hres) || V_VT(&v) != VT_UNKNOWN)
{
ERRORTRACE((LOG_ESS, "Invalid instance deletion event without "
"TargetInstance recieved by monitor '%S'\n",
m_pOuter->m_wszDataQuery));
continue;
}
CClearMe cm(&v);
_IWmiObject* pObj;
hres = V_UNKNOWN(&v)->QueryInterface(IID__IWmiObject, (void**)&pObj);
CReleaseMe rm(pObj);
hres = m_pOuter->ProcessDelete(pObj, true);
}
return WBEM_S_NO_ERROR;
}
HRESULT CMonitor::CModificationOutSink::Indicate(long lNumEvents,
IWbemEvent** apEvents,
CEventContext* pContext)
{
HRESULT hres;
for(long i = 0; i < lNumEvents; i++)
{
//
// Extract its TargetInstance and remove it
//
VARIANT v;
hres = apEvents[i]->Get(L"TargetInstance", 0, &v, NULL, NULL);
if(FAILED(hres) || V_VT(&v) != VT_UNKNOWN)
{
ERRORTRACE((LOG_ESS, "Invalid instance deletion event without "
"TargetInstance recieved by monitor '%S'\n",
m_pOuter->m_wszDataQuery));
continue;
}
CClearMe cm(&v);
_IWmiObject* pObj;
hres = V_UNKNOWN(&v)->QueryInterface(IID__IWmiObject, (void**)&pObj);
CReleaseMe rm(pObj);
hres = m_pOuter->ProcessModOut(pObj, true);
}
return WBEM_S_NO_ERROR;
}
STDMETHODIMP CMonitor::CDataSink::Indicate(long lNumObjects,
IWbemClassObject** apObjects)
{
HRESULT hres;
for(long i = 0; i < lNumObjects; i++)
{
//
// Just add it
//
_IWmiObject* pObj;
hres = apObjects[i]->QueryInterface(IID__IWmiObject, (void**)&pObj);
CReleaseMe rm(pObj);
hres = m_pOuter->ProcessPossibleAdd(pObj, false);
}
return WBEM_S_NO_ERROR;
}
STDMETHODIMP CMonitor::CDataSink::SetStatus(long lFlags, HRESULT hresResult,
BSTR, IWbemClassObject* pError)
{
if(lFlags != WBEM_STATUS_COMPLETE)
return WBEM_S_NO_ERROR;
m_pOuter->ProcessDataDone(hresResult, pError);
return WBEM_S_NO_ERROR;
}
HRESULT CMonitor::ProcessPollObject(_IWmiObject* pObj)
{
HRESULT hres;
//
// An object came back from the query --- mark it in the table as 'present'
//
//
// Get its path
//
VARIANT v;
VariantInit(&v);
hres = pObj->Get(L"__RELPATH", 0, &v, NULL, NULL);
if(FAILED(hres) || V_VT(&v) != VT_BSTR)
return WBEM_E_CRITICAL_ERROR;
CClearMe cm(&v);
LPCWSTR wszPath = V_BSTR(&v);
//
// Determine if firing is necessary
//
bool bFire;
DWORD dwObjectCount;
{
CInCritSec ics(&m_cs);
//
// See if we already have it
//
TIterator it = m_map.find(wszPath);
if(it == m_map.end())
{
// This instance was not there before --- fire an assert!
bFire = true;
dwObjectCount = m_map.size();
}
else
{
// It's already there
bFire = false;
}
//
// Set the presense indicator to true --- otherwise we will delete it
// when the query is over
//
m_map[wszPath] = true;
}
if(bFire)
FireAssert(pObj, wszPath, m_bFirstPollDone, dwObjectCount);
return WBEM_S_NO_ERROR;
}
HRESULT CMonitor::ProcessPollQueryDone(HRESULT hresQuery,
IWbemClassObject* pError)
{
//
// The polling query has finished, so anything in the map marked with
// 'false' for the presence indicator has not come in this time and we must
// fire a retract. At the same time, we will reset all the presense
// indicators for the next time
//
CWStringArray awsRetracts;
DWORD dwCountBefore;
{
CInCritSec ics(&m_cs);
dwCountBefore = m_map.size();
//
// note --- for loop not incrementing iterator. This is because
// sometimes we have to remove things from the map
//
for(TIterator it = m_map.begin(); it != m_map.end(); )
{
if(!it->second)
{
// Not there --- write down for retract
if(awsRetracts.Add(it->first) < 0)
return WBEM_E_OUT_OF_MEMORY;
//
// Remove this guy from the map. This will advance the
// iterator
//
it = m_map.erase(it);
}
else
{
// It is there --- reset the indicator
it->second = true;
it++;
}
}
}
//
// Fire all the retracts we have accomulated
//
for(int i = 0; i < awsRetracts.Size(); i++)
{
FireRetract(NULL, awsRetracts[i], true, dwCountBefore - i);
}
//
// Set the "done with the first query" indicator
//
m_bFirstPollDone = true;
return S_OK;
}
/*
QL_LEVEL_1_RPN_EXPRESSION* pEventQ = new QL_LEVEL_1_RPN_EXPRESSION;
//
// Add all the properties that the data query was looking for, but with
// TargetInstance
//
for(int i = 0; i < pDataQ->nNumberOfProperties; i++)
{
CPropertuName& OldName = pDataQ->pRequestedPropertyNames[i];
CPropertyName NewName;
NewName.AddElement(L"TargetInstance")
for(int j = 0; j < OldName.GetNumElements(); i++)
{
NewName.AddElement(OldName.GetStringAt(i))
}
pEventQ->AddProperty(NewName);
}
//
// Add "TargetInstance isa "MyClass"" there
//
QL_LEVEL_1_TOKEN Token;
Token.PropertyName.AddElement(L"TargetInstance");
Token.nTokenType = QL1_OP_EXPRESSION;
Token.nOperator = QL1_OPERATOR_ISA;
V_VT(&Token.vConstValue) = VT_BSTR;
V_BSTR(&Token.vConstValue) = SysAllocString(pDataQ->bsClassName);
Token.m_bPropComp = FALSE;
Token.dwPropertyFunction = Token.dwConstFunction = 0;
pEventQ->AddToken(Token);
//
// Convert the original query to DNF
//
CDNFExpression DNF;
QL_LEVEL_1_TOKEN* aTokens = pDataQ->pArrayOfTokens;
DNF.ConstructFromTokens(aTokens);
//
// Reduce it to just the part about the keys
//
CDNFExpression* pKeyDNF = NULL;
hres = DNF.GetNecessaryProjection(&Filter, &pKeyDNF);
if(FAILED(hres))
return hres;
//
// Stick those back into the event query
//
if(pKeyDNF->GetNumTerms() > 0)
{
hres = pKeyDNF->AddToRPN(pEventQ);
if(FAILED(hres))
return hres;
Token.nTokenType = QL1_AND;
pEventQ->AddToken(Token);
}
//
// At this point, our creation and deletion queries are complete.
// But for our modification query, we need to add all the properties we
// are interested in with TargetInstance.X <> PreviousInstance.X
//
QL_LEVEL_1_RPN_EXPRESSION* pModEventQ =
new QL_LEVEL_1_RPN_EXPRESSION(*pEventQ);
//
// Add all the properties that the data query was looking for, but with
// TargetInstance.X <> PreviousInstance.X
//
for(int i = 0; i < pDataQ->nNumberOfProperties; i++)
{
CPropertuName& OldName = pDataQ->pRequestedPropertyNames[i];
Token.PropertyName.Empty();
Token.PropertyName2.Empty();
Token.PropertyName.AddElement(L"TargetInstance")
Token.PropertyName2.AddElement(L"PreviousInstance")
for(int j = 0; j < OldName.GetNumElements(); i++)
{
Token.PropertyName.AddElement(OldName.GetStringAt(i))
Token.PropertyName2.AddElement(OldName.GetStringAt(i))
}
Token.m_bPropComp = TRUE;
Token.nTokenType = QL1_OP_EXPRESSION;
Token.nOperator = QL1_OPERATOR_NOTEQUALS;
pModEventQ->AddToken(Token);
Token.nTokenType = QL1_AND;
pModEventQ->AddToken(Token);
}
//
// Construct results
//
*ppCreationEventQ = new QL_LEVEL_1_RPN_EXPRESSION(*pEventQ);
pEventQ->SetClassName(L"__InstanceCreationEvent");
*ppDeletionEventQ = new QL_LEVEL_1_RPN_EXPRESSION(*pEventQ);
pEventQ->SetClassName(L"__InstanceDeletionEvent");
*pp
*/