You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2235 lines
66 KiB
2235 lines
66 KiB
/******************************************************************************
|
|
|
|
Copyright (c) 1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
DataCollection.cpp
|
|
|
|
Abstract:
|
|
This file contains the implementation of the CSAFDataCollection class,
|
|
which implements the data collection functionality.
|
|
|
|
Revision History:
|
|
Davide Massarenti (Dmassare) 07/22/99
|
|
created
|
|
|
|
******************************************************************************/
|
|
|
|
#include "stdafx.h"
|
|
|
|
#include "wmixmlt.h"
|
|
#include <wbemcli.h>
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
#define CHECK_MODIFY() __MPC_EXIT_IF_METHOD_FAILS(hr, CanModifyProperties())
|
|
#define CHECK_ABORTED() __MPC_EXIT_IF_METHOD_FAILS(hr, IsCollectionAborted())
|
|
|
|
#define DATASPEC_DEFAULT L"<systemdataspec>"
|
|
#define DATASPEC_CONFIG HC_ROOT_HELPSVC_CONFIG L"\\Dataspec.xml"
|
|
#define DATASPEC_LOCATION HC_ROOT_HELPSVC_DATACOLL
|
|
#define DATASPEC_TEMP HC_ROOT_HELPSVC_TEMP
|
|
|
|
#define SAFETY_MARGIN__MEMORY (4*1024*1024)
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
#define TEXT_TAG_DATACOLLECTION L"DataCollection"
|
|
|
|
#define TEXT_TAG_SNAPSHOT L"Snapshot"
|
|
#define TEXT_ATTR_TIMESTAMP L"Timestamp"
|
|
#define TEXT_ATTR_TIMEZONE L"TimeZone"
|
|
|
|
#define TEXT_TAG_DELTA L"Delta"
|
|
#define TEXT_ATTR_TIMESTAMP_T0 L"Timestamp_T0"
|
|
#define TEXT_ATTR_TIMESTAMP_T1 L"Timestamp_T1"
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
static WCHAR l_CIM_header [] = L"<?xml version=\"1.0\" encoding=\"unicode\"?><CIM CIMVERSION=\"2.0\" DTDVERSION=\"2.0\"><DECLARATION><DECLGROUP.WITHPATH>";
|
|
static WCHAR l_CIM_trailer[] = L"</DECLGROUP.WITHPATH></DECLARATION></CIM>";
|
|
static WCHAR l_Select_Pattern[] = L"Select";
|
|
|
|
static CComVariant l_vPathLevel ( 3 );
|
|
static CComVariant l_vExcludeSystemProperties ( (bool)true );
|
|
|
|
static CComBSTR l_bstrQueryLang ( L"WQL" );
|
|
static CComBSTR l_bstrPathLevel ( L"PathLevel" );
|
|
static CComBSTR l_bstrExcludeSystemProperties( L"ExcludeSystemProperties" );
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
void CSAFDataCollection::CleanQueryResult( QueryResults& qr )
|
|
{
|
|
MPC::CallDestructorForAll( qr );
|
|
}
|
|
|
|
HRESULT CSAFDataCollection::StreamFromXML( /*[in]*/ IXMLDOMDocument* xdd ,
|
|
/*[in]*/ bool fDelete ,
|
|
/*[in/out]*/ CComPtr<IStream>& val )
|
|
{
|
|
__HCP_FUNC_ENTRY( "CSAFDataCollection::StreamFromXML" );
|
|
|
|
HRESULT hr;
|
|
CComPtr<MPC::FileStream> stream;
|
|
MPC::wstring strTempFile;
|
|
|
|
|
|
//
|
|
// No XML document, so no stream...
|
|
//
|
|
if(xdd)
|
|
{
|
|
MPC::wstring strTempPath;
|
|
LARGE_INTEGER li;
|
|
|
|
|
|
//
|
|
// Generate a unique file name.
|
|
//
|
|
strTempPath = DATASPEC_TEMP; MPC::SubstituteEnvVariables( strTempPath );
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, MPC::GetTemporaryFileName( strTempFile, strTempPath.c_str() ));
|
|
|
|
//
|
|
// Create a stream for a file.
|
|
//
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, MPC::CreateInstance( &stream ));
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, stream->InitForReadWrite( strTempFile.c_str() ));
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, stream->DeleteOnRelease ( fDelete ));
|
|
|
|
|
|
//
|
|
// Write the XML DOM to the stream.
|
|
//
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, xdd->save( CComVariant( stream ) ));
|
|
|
|
|
|
//
|
|
// Reset stream to beginning.
|
|
//
|
|
li.LowPart = 0;
|
|
li.HighPart = 0;
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, stream->Seek( li, STREAM_SEEK_SET, NULL ));
|
|
}
|
|
|
|
val = stream;
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
stream.Release();
|
|
|
|
(void)MPC::RemoveTemporaryFile( strTempFile );
|
|
}
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
CSAFDataCollection::CSAFDataCollection()
|
|
{
|
|
__HCP_FUNC_ENTRY( "CSAFDataCollection::CSAFDataCollection" );
|
|
|
|
|
|
// MPC::Impersonation m_imp;
|
|
//
|
|
m_dsStatus = DC_NOTACTIVE; // DC_STATUS m_dsStatus;
|
|
m_lPercent = 0; // long m_lPercent;
|
|
m_dwErrorCode = S_OK; // DWORD m_dwErrorCode;
|
|
m_fScheduled = false; // bool m_fScheduled;
|
|
m_fCompleted = false; // bool m_fCompleted;
|
|
m_fWorking = false; // bool m_fWorking;
|
|
// List m_lstReports;
|
|
m_hcpdcrcCurrentReport = NULL; // CSAFDataCollectionReport* m_hcpdcrcCurrentReport;
|
|
//
|
|
// CComBSTR m_bstrMachineData;
|
|
// CComBSTR m_bstrHistory;
|
|
m_lHistory = 0; // long m_lHistory;
|
|
//
|
|
// CComPtr<IStream> m_streamMachineData;
|
|
// CComPtr<IStream> m_streamHistory;
|
|
//
|
|
//
|
|
// CComBSTR m_bstrFilenameT0;
|
|
// CComBSTR m_bstrFilenameT1;
|
|
// CComBSTR m_bstrFilenameDiff;
|
|
//
|
|
//
|
|
// CComPtrThreadNeutral<IDispatch> m_sink_onStatusChange;
|
|
// CComPtrThreadNeutral<IDispatch> m_sink_onProgress;
|
|
// CComPtrThreadNeutral<IDispatch> m_sink_onComplete;
|
|
//
|
|
m_lQueries_Done = 0; // long m_lQueries_Done;
|
|
m_lQueries_Total = 0; // long m_lQueries_Total;
|
|
}
|
|
|
|
HRESULT CSAFDataCollection::FinalConstruct()
|
|
{
|
|
__HCP_FUNC_ENTRY( "CSAFDataCollection::FinalConstruct" );
|
|
|
|
__HCP_FUNC_EXIT(S_OK);
|
|
}
|
|
|
|
void CSAFDataCollection::FinalRelease()
|
|
{
|
|
__HCP_FUNC_ENTRY( "CSAFDataCollection::FinalRelease" );
|
|
|
|
(void)Abort();
|
|
|
|
Thread_Wait();
|
|
|
|
EraseReports();
|
|
}
|
|
|
|
void CSAFDataCollection::EraseReports()
|
|
{
|
|
__HCP_FUNC_ENTRY( "CSAFDataCollection::EraseReports" );
|
|
|
|
IterConst it;
|
|
MPC::SmartLock<_ThreadModel> lock( this );
|
|
|
|
|
|
//
|
|
// Release all the items.
|
|
//
|
|
MPC::ReleaseAll( m_lstReports );
|
|
m_hcpdcrcCurrentReport = NULL;
|
|
|
|
m_streamMachineData = NULL;
|
|
m_streamHistory = NULL;
|
|
}
|
|
|
|
void CSAFDataCollection::StartOperations()
|
|
{
|
|
__HCP_FUNC_ENTRY( "CSAFDataCollection::StartOperation" );
|
|
|
|
MPC::SmartLock<_ThreadModel> lock( this );
|
|
|
|
|
|
EraseReports();
|
|
|
|
m_fWorking = true;
|
|
m_fCompleted = false;
|
|
}
|
|
|
|
void CSAFDataCollection::StopOperations()
|
|
{
|
|
__HCP_FUNC_ENTRY( "CSAFDataCollection::StartOperation" );
|
|
|
|
MPC::SmartLock<_ThreadModel> lock( this );
|
|
|
|
|
|
m_fWorking = false;
|
|
}
|
|
|
|
HRESULT CSAFDataCollection::ImpersonateCaller()
|
|
{
|
|
return m_imp.Impersonate();
|
|
}
|
|
|
|
HRESULT CSAFDataCollection::EndImpersonation()
|
|
{
|
|
return m_imp.RevertToSelf();
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
HRESULT CSAFDataCollection::ExecLoopCollect()
|
|
{
|
|
__HCP_FUNC_ENTRY( "CSAFDataCollection::ExecLoopCollect" );
|
|
|
|
HRESULT hr;
|
|
QueryResults qr;
|
|
WMIHistory::Database wmihd;
|
|
WMIHistory::Database wmihd_MachineData;
|
|
WMIHistory::Database wmihd_History;
|
|
WMIHistory::Database::ProvList lstQueries_MachineData;
|
|
WMIHistory::Database::ProvList lstQueries_History;
|
|
DC_STATUS dcLastState;
|
|
|
|
|
|
::SetThreadPriority( ::GetCurrentThread(), THREAD_PRIORITY_LOWEST );
|
|
|
|
__MPC_TRY_BEGIN();
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, put_Status( DC_COLLECTING )); dcLastState = DC_COLLECTING;
|
|
|
|
CHECK_ABORTED();
|
|
|
|
//
|
|
// First of all, load and validate the dataspec.
|
|
//
|
|
if(m_bstrMachineData.Length())
|
|
{
|
|
if(MPC::StrICmp( m_bstrMachineData, DATASPEC_DEFAULT ) == 0)
|
|
{
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, wmihd_MachineData.Init( NULL, DATASPEC_CONFIG ));
|
|
}
|
|
else
|
|
{
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, ImpersonateCaller());
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, wmihd_MachineData.Init( NULL, m_bstrMachineData ));
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, EndImpersonation());
|
|
}
|
|
|
|
//
|
|
// Filter and count the queries.
|
|
//
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, FilterDataSpec( wmihd_MachineData, NULL, lstQueries_MachineData ));
|
|
}
|
|
|
|
if(m_bstrHistory.Length())
|
|
{
|
|
//
|
|
// Try to lock the database and load the data spec file.
|
|
//
|
|
while(1)
|
|
{
|
|
if(SUCCEEDED(hr = wmihd.Init( DATASPEC_LOCATION, DATASPEC_CONFIG )))
|
|
{
|
|
break;
|
|
}
|
|
|
|
if(hr != HRESULT_FROM_WIN32( WAIT_TIMEOUT ))
|
|
{
|
|
__MPC_FUNC_LEAVE;
|
|
}
|
|
|
|
CHECK_ABORTED();
|
|
}
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, wmihd.Load());
|
|
|
|
|
|
//
|
|
// Filter and count the queries.
|
|
//
|
|
if(MPC::StrICmp( m_bstrHistory, DATASPEC_DEFAULT ) == 0)
|
|
{
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, wmihd_History.Init( NULL, DATASPEC_CONFIG ));
|
|
}
|
|
else
|
|
{
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, ImpersonateCaller());
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, wmihd_History.Init( NULL, m_bstrHistory ));
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, EndImpersonation());
|
|
}
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, FilterDataSpec( wmihd, &wmihd_History, lstQueries_History ));
|
|
}
|
|
|
|
//
|
|
// Then count the number of queries to be executed.
|
|
//
|
|
m_lQueries_Done = 0;
|
|
m_lQueries_Total = lstQueries_MachineData.size() + lstQueries_History.size();
|
|
|
|
CHECK_ABORTED();
|
|
|
|
//
|
|
// Execute the collection of Machine Data.
|
|
//
|
|
if(m_bstrMachineData.Length())
|
|
{
|
|
WMIParser::ClusterByClassMap cluster;
|
|
CComPtr<IXMLDOMDocument> xdd;
|
|
|
|
|
|
//
|
|
// Collect data from WMI.
|
|
//
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, ExecDataSpec( qr, cluster, lstQueries_MachineData, true ));
|
|
|
|
//
|
|
// Collate all the different streams into only one XML document.
|
|
//
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, CollateMachineDataWithTimestamp( qr, cluster, NULL, NULL, &xdd ));
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, StreamFromXML( xdd, true, m_streamMachineData ));
|
|
|
|
//
|
|
// Cleanup everything.
|
|
//
|
|
cluster.clear();
|
|
CleanQueryResult( qr );
|
|
}
|
|
|
|
CHECK_ABORTED();
|
|
|
|
if(m_bstrHistory.Length())
|
|
{
|
|
WMIParser::ClusterByClassMap cluster;
|
|
CComPtr<IXMLDOMDocument> xdd;
|
|
|
|
//
|
|
// Collect data from WMI.
|
|
//
|
|
// We actually use the queries in our data spec and do only those specified in the history list.
|
|
//
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, ExecDataSpec( qr, cluster, lstQueries_History, false ));
|
|
|
|
|
|
//
|
|
// Compute deltas, but don't persist them! (fPersist == false)
|
|
//
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, ComputeDelta( qr, cluster, lstQueries_History, false ));
|
|
|
|
//
|
|
// Cleanup everything (the data is already stored in files...)
|
|
//
|
|
cluster.clear();
|
|
CleanQueryResult( qr );
|
|
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, try_Status( dcLastState, DC_COMPARING )); dcLastState = DC_COMPARING;
|
|
|
|
//
|
|
// Collate all the different snapshots and deltas into only one XML document.
|
|
//
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, CollateHistory( wmihd, wmihd_History, &xdd ));
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, StreamFromXML( xdd, true, m_streamHistory ));
|
|
}
|
|
|
|
CHECK_ABORTED();
|
|
|
|
Fire_onProgress( this, m_lQueries_Done, m_lQueries_Total );
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, try_Status( dcLastState, DC_COMPLETED )); dcLastState = DC_COMPLETED;
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
__MPC_TRY_CATCHALL(hr);
|
|
|
|
(void)EndImpersonation();
|
|
|
|
//
|
|
//
|
|
//
|
|
if(FAILED(hr))
|
|
{
|
|
(void)put_ErrorCode( hr );
|
|
(void)put_Status ( DC_FAILED );
|
|
}
|
|
|
|
//
|
|
// Make sure to delete the temporary WMIParser:Snapshot objects.
|
|
//
|
|
CleanQueryResult( qr );
|
|
|
|
//
|
|
// In any case, fire the "onComplete" event, so all the clients exit from loops.
|
|
//
|
|
Fire_onComplete( this, hr );
|
|
|
|
Thread_Abort(); // To tell the MPC:Thread object to close the worker thread...
|
|
|
|
//
|
|
// Anyway, always return a success.
|
|
//
|
|
StopOperations();
|
|
hr = S_OK;
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
HRESULT CSAFDataCollection::ExecLoopCompare()
|
|
{
|
|
__HCP_FUNC_ENTRY( "CSAFDataCollection::ExecLoopCompare" );
|
|
|
|
HRESULT hr;
|
|
VARIANT_BOOL fRes;
|
|
DC_STATUS dcLastState;
|
|
|
|
|
|
::SetThreadPriority( ::GetCurrentThread(), THREAD_PRIORITY_LOWEST );
|
|
|
|
__MPC_TRY_BEGIN();
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, put_Status( DC_COMPARING )); dcLastState = DC_COMPARING;
|
|
|
|
CHECK_ABORTED();
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, ImpersonateCaller());
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, WMIParser::CompareSnapshots( m_bstrFilenameT0, m_bstrFilenameT1, m_bstrFilenameDiff, &fRes ));
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, EndImpersonation());
|
|
|
|
if(fRes == VARIANT_FALSE)
|
|
{
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, try_Status( dcLastState, DC_NODELTA )); dcLastState = DC_NODELTA;
|
|
}
|
|
else
|
|
{
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, try_Status( dcLastState, DC_COMPLETED )); dcLastState = DC_COMPLETED;
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
__MPC_TRY_CATCHALL(hr);
|
|
|
|
(void)EndImpersonation();
|
|
|
|
//
|
|
//
|
|
//
|
|
if(FAILED(hr))
|
|
{
|
|
(void)put_ErrorCode( hr );
|
|
(void)put_Status ( DC_FAILED );
|
|
}
|
|
|
|
//
|
|
// In any case, fire the "onComplete" event, so all the clients exit from loops.
|
|
//
|
|
Fire_onComplete( this, hr );
|
|
|
|
Thread_Abort(); // To tell the MPC:Thread object to close the worker thread...
|
|
|
|
//
|
|
// Anyway, always return a success.
|
|
//
|
|
StopOperations();
|
|
hr = S_OK;
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
HRESULT CSAFDataCollection::FilterDataSpec( /*[in]*/ WMIHistory::Database& wmihdQuery ,
|
|
/*[in]*/ WMIHistory::Database* wmihdFilter ,
|
|
/*[in]*/ WMIHistory::Database::ProvList& lstQueries )
|
|
{
|
|
__HCP_FUNC_ENTRY( "CSAFDataCollection::FilterDataSpec" );
|
|
|
|
HRESULT hr;
|
|
WMIHistory::Database::ProvIterConst itBegin;
|
|
WMIHistory::Database::ProvIterConst itEnd;
|
|
WMIHistory::Database::ProvIterConst it;
|
|
|
|
|
|
//
|
|
// Exec each query.
|
|
//
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, wmihdQuery.get_Providers( itBegin, itEnd ));
|
|
for(it=itBegin; it!=itEnd; it++)
|
|
{
|
|
WMIHistory::Provider* wmihp = *it;
|
|
MPC::wstring szNamespace;
|
|
MPC::wstring szClass;
|
|
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, wmihp->get_Namespace( szNamespace ));
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, wmihp->get_Class ( szClass ));
|
|
|
|
|
|
if(wmihdFilter)
|
|
{
|
|
WMIHistory::Provider* wmihpFilter;
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, wmihdFilter->find_Provider( NULL, &szNamespace, &szClass, wmihpFilter ));
|
|
|
|
//
|
|
// The namespace/class is unknown, skip it.
|
|
//
|
|
if(wmihpFilter == NULL) continue;
|
|
}
|
|
|
|
lstQueries.push_back( wmihp );
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
|
|
HRESULT CSAFDataCollection::ExecDataSpec( /*[in/out]*/ QueryResults& qr ,
|
|
/*[in/out]*/ WMIParser::ClusterByClassMap& cluster ,
|
|
/*[in]*/ WMIHistory::Database::ProvList& lstQueries ,
|
|
/*[in]*/ bool fImpersonate )
|
|
{
|
|
__HCP_FUNC_ENTRY( "CSAFDataCollection::ExecDataSpec" );
|
|
|
|
HRESULT hr;
|
|
WMIHistory::Database::ProvIterConst itBegin = lstQueries.begin();
|
|
WMIHistory::Database::ProvIterConst itEnd = lstQueries.end();
|
|
WMIHistory::Database::ProvIterConst it;
|
|
|
|
|
|
//
|
|
// Exec each query.
|
|
//
|
|
for(it=itBegin; it!=itEnd; it++)
|
|
{
|
|
CComPtr<IXMLDOMDocument> xddCollected;
|
|
WMIHistory::Provider* wmihp = *it;
|
|
MPC::wstring szNamespace;
|
|
MPC::wstring szClass;
|
|
MPC::wstring szWQL;
|
|
|
|
|
|
Fire_onProgress( this, m_lQueries_Done++, m_lQueries_Total );
|
|
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, wmihp->get_Namespace( szNamespace ));
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, wmihp->get_Class ( szClass ));
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, wmihp->get_WQL ( szWQL ));
|
|
|
|
if(szWQL.length() == 0)
|
|
{
|
|
szWQL = L"select * from ";
|
|
szWQL += szClass;
|
|
}
|
|
|
|
//
|
|
// Create a new item and link it to the system.
|
|
//
|
|
{
|
|
CSAFDataCollectionReport* dcr;
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, MPC::CreateInstance( &dcr ));
|
|
m_lstReports.push_back( dcr );
|
|
|
|
dcr->m_bstrNamespace = szNamespace.c_str();
|
|
dcr->m_bstrClass = szClass .c_str();
|
|
dcr->m_bstrWQL = szWQL .c_str();
|
|
m_hcpdcrcCurrentReport = dcr;
|
|
}
|
|
|
|
|
|
//
|
|
// Fix for a problem in WMI: namespaces with "/" are not recognized...
|
|
//
|
|
{
|
|
MPC::wstring::size_type pos;
|
|
|
|
while((pos = szNamespace.find( '/' )) != szNamespace.npos) szNamespace[pos] = '\\';
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Execute the query, impersonating if requested.
|
|
//
|
|
if(fImpersonate)
|
|
{
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, ImpersonateCaller());
|
|
}
|
|
|
|
hr = CollectUsingEncoder( szNamespace, szWQL, &xddCollected );
|
|
if(FAILED(hr))
|
|
{
|
|
xddCollected = NULL;
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, CollectUsingTranslator( szNamespace, szWQL, &xddCollected ));
|
|
}
|
|
|
|
if(fImpersonate)
|
|
{
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, EndImpersonation());
|
|
}
|
|
//
|
|
//
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////////
|
|
|
|
if(xddCollected)
|
|
{
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, Distribute( xddCollected, qr, cluster ));
|
|
}
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
(void)EndImpersonation();
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
HRESULT CSAFDataCollection::CollectUsingTranslator( /*[in] */ MPC::wstring& szNamespace ,
|
|
/*[in] */ MPC::wstring& szWQL ,
|
|
/*[out]*/ IXMLDOMDocument* *ppxddDoc )
|
|
{
|
|
__HCP_FUNC_ENTRY( "CSAFDataCollection::CollectUsingTranslator" );
|
|
|
|
HRESULT hr;
|
|
HRESULT hrXML;
|
|
CComBSTR bstrNamespace = szNamespace.c_str();
|
|
CComBSTR bstrWQL = szWQL .c_str();
|
|
CComPtr<IWmiXMLTranslator> pTrans;
|
|
CComPtr<IXMLDOMDocument> xddDoc;
|
|
CComBSTR bstrXML;
|
|
VARIANT_BOOL fSuccessful;
|
|
|
|
|
|
*ppxddDoc = NULL;
|
|
CHECK_ABORTED();
|
|
|
|
|
|
//
|
|
// Create the WMI->XML translator.
|
|
//
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, ::CoCreateInstance( CLSID_WmiXMLTranslator, NULL, CLSCTX_INPROC_SERVER, IID_IWmiXMLTranslator, (void**)&pTrans ));
|
|
|
|
// Set to truncate Qualifiers and have full identity information.
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, pTrans->put_DeclGroupType ( wmiXMLDeclGroupWithPath ));
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, pTrans->put_QualifierFilter( wmiXMLFilterNone ));
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, pTrans->put_HostFilter ( VARIANT_TRUE ));
|
|
|
|
//
|
|
// Execute the query.
|
|
//
|
|
hrXML = pTrans->ExecQuery( bstrNamespace, bstrWQL, &bstrXML );
|
|
if(FAILED(hrXML))
|
|
{
|
|
CComQIPtr<ISupportErrorInfo> sei = pTrans;
|
|
|
|
if(sei && SUCCEEDED(sei->InterfaceSupportsErrorInfo( IID_IWmiXMLTranslator )))
|
|
{
|
|
CComPtr<IErrorInfo> ei;
|
|
|
|
if(SUCCEEDED(GetErrorInfo( 0, &ei )) && ei)
|
|
{
|
|
ei->GetDescription( &m_hcpdcrcCurrentReport->m_bstrDescription );
|
|
}
|
|
}
|
|
|
|
m_hcpdcrcCurrentReport->m_dwErrorCode = hrXML;
|
|
|
|
__MPC_SET_ERROR_AND_EXIT(hr, S_FALSE);
|
|
}
|
|
|
|
//
|
|
// Load the result into an XML DOM object.
|
|
//
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, ::CoCreateInstance( CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER, IID_IXMLDOMDocument, (void**)&xddDoc ));
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, xddDoc->loadXML( bstrXML, &fSuccessful ));
|
|
if(fSuccessful == VARIANT_FALSE)
|
|
{
|
|
CComQIPtr<ISupportErrorInfo> sei = xddDoc;
|
|
|
|
if(sei && SUCCEEDED(sei->InterfaceSupportsErrorInfo( IID_IXMLDOMDocument )))
|
|
{
|
|
CComPtr<IErrorInfo> ei;
|
|
|
|
if(SUCCEEDED(GetErrorInfo( 0, &ei )))
|
|
{
|
|
ei->GetDescription( &m_hcpdcrcCurrentReport->m_bstrDescription );
|
|
}
|
|
}
|
|
|
|
m_hcpdcrcCurrentReport->m_dwErrorCode = ERROR_BAD_FORMAT;
|
|
|
|
__MPC_SET_ERROR_AND_EXIT(hr, S_FALSE);
|
|
}
|
|
|
|
|
|
// __MPC_EXIT_IF_METHOD_FAILS(hr, xddDoc->save( CComVariant( "C:\\dump.xml" ) ));
|
|
|
|
// __MPC_EXIT_IF_METHOD_FAILS(hr, xddDoc->load( CComVariant( "C:\\dump.xml" ), &fSuccessful ));
|
|
// if(fSuccessful == VARIANT_FALSE)
|
|
// {
|
|
// __MPC_SET_WIN32_ERROR_AND_EXIT(hr, ERROR_BAD_FORMAT);
|
|
// }
|
|
|
|
|
|
//
|
|
// Return the pointer to the XML document.
|
|
//
|
|
*ppxddDoc = xddDoc.Detach();
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
HRESULT CSAFDataCollection::CollectUsingEncoder( /*[in] */ MPC::wstring& szNamespace ,
|
|
/*[in] */ MPC::wstring& szWQL ,
|
|
/*[out]*/ IXMLDOMDocument* *ppxddDoc )
|
|
{
|
|
__HCP_FUNC_ENTRY( "CSAFDataCollection::CollectUsingEncoder" );
|
|
|
|
HRESULT hr;
|
|
HRESULT hrXML;
|
|
HRESULT hrConnect;
|
|
CComBSTR bstrNamespace( szNamespace.c_str() );
|
|
CComBSTR bstrWQL ( szWQL .c_str() );
|
|
CComPtr<IXMLDOMDocument> xddDoc;
|
|
CComBSTR bstrXML;
|
|
VARIANT_BOOL fSuccessful;
|
|
|
|
// Additional Declarations/Definitions for XMLE Usage.
|
|
|
|
CComPtr<IWbemContext> pWbemContext;
|
|
CComPtr<IWbemServices> pWbemServices;
|
|
CComPtr<IWbemObjectTextSrc> pWbemTextSrc;
|
|
CComPtr<IEnumWbemClassObject> pWbemEnum;
|
|
CComPtr<IWbemLocator> pWbemLocator;
|
|
|
|
LPWSTR szSelect;
|
|
LPWSTR szWQLCopy;
|
|
|
|
CComBSTR bstrModWQL;
|
|
|
|
*ppxddDoc = NULL;
|
|
CHECK_ABORTED();
|
|
|
|
|
|
// Create an instance of WbemObjectTextSrc class (this would fails if the Encoder functionality is not present).
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, ::CoCreateInstance( CLSID_WbemObjectTextSrc, NULL, CLSCTX_INPROC_SERVER, IID_IWbemObjectTextSrc, (void**)&pWbemTextSrc ));
|
|
|
|
// Create an instance of the IWbemLocator Interface.
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, ::CoCreateInstance( CLSID_WbemLocator, NULL, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID *)&pWbemLocator ));
|
|
|
|
|
|
//
|
|
// Got the pointer to the IWbemLocator Service.
|
|
//
|
|
// Connect to the required Namespace using the Locator Service.
|
|
//
|
|
hrConnect = pWbemLocator->ConnectServer( CComBSTR( szNamespace.c_str() ),
|
|
NULL , //using current account for simplicity
|
|
NULL , //using current password for simplicity
|
|
0L , // locale
|
|
0L , // securityFlags
|
|
NULL , // authority (domain for NTLM)
|
|
NULL , // context
|
|
&pWbemServices );
|
|
|
|
if(FAILED(hrConnect))
|
|
{
|
|
CComQIPtr<ISupportErrorInfo> sei = pWbemLocator;
|
|
|
|
if(sei && SUCCEEDED(sei->InterfaceSupportsErrorInfo( IID_IWbemLocator )))
|
|
{
|
|
CComPtr<IErrorInfo> ei;
|
|
|
|
if(SUCCEEDED(GetErrorInfo( 0, &ei )) && ei)
|
|
{
|
|
ei->GetDescription( &m_hcpdcrcCurrentReport->m_bstrDescription );
|
|
}
|
|
}
|
|
|
|
m_hcpdcrcCurrentReport->m_dwErrorCode = hrConnect;
|
|
|
|
__MPC_SET_ERROR_AND_EXIT(hr, S_FALSE);
|
|
}
|
|
|
|
//
|
|
// Adjust the security level to IMPERSONATE, to satisfy the flawed WMI requirements....
|
|
//
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, MPC::SetInterfaceSecurity_ImpLevel( pWbemServices, RPC_C_IMP_LEVEL_IMPERSONATE ));
|
|
|
|
|
|
//
|
|
// Connected To Namespace.
|
|
//
|
|
// Now execute the query to get EnumObjects.
|
|
// This is the instances got against the query.
|
|
// WBEM_FLAG_FORWARD_ONLY Flag to be used?
|
|
//
|
|
|
|
// Append __Path to the WQL query.
|
|
|
|
szWQLCopy = bstrWQL;
|
|
|
|
// Search for Select pattern.
|
|
szSelect = StrStrIW(szWQLCopy,l_Select_Pattern);
|
|
|
|
if(szSelect != NULL)
|
|
{
|
|
// Select Pattern Found
|
|
|
|
// Advance the pointer to the end of the pattern so the pointer is
|
|
// positioned at end of the word "select"
|
|
|
|
szSelect += wcslen(l_Select_Pattern);
|
|
|
|
bstrModWQL = L"Select __Path, ";
|
|
bstrModWQL.Append(szSelect);
|
|
|
|
bstrWQL = bstrModWQL;
|
|
}
|
|
|
|
hrXML = pWbemServices->ExecQuery( l_bstrQueryLang, bstrWQL, 0, 0, &pWbemEnum );
|
|
if(FAILED(hrXML))
|
|
{
|
|
CComQIPtr<ISupportErrorInfo> sei = pWbemServices;
|
|
|
|
if(sei && SUCCEEDED(sei->InterfaceSupportsErrorInfo( IID_IWbemServices )))
|
|
{
|
|
CComPtr<IErrorInfo> ei;
|
|
|
|
if(SUCCEEDED(GetErrorInfo( 0, &ei )) && ei)
|
|
{
|
|
ei->GetDescription( &m_hcpdcrcCurrentReport->m_bstrDescription );
|
|
}
|
|
}
|
|
|
|
m_hcpdcrcCurrentReport->m_dwErrorCode = hrXML;
|
|
|
|
__MPC_SET_ERROR_AND_EXIT(hr, S_FALSE);
|
|
}
|
|
|
|
//
|
|
// Adjust the security level to IMPERSONATE, to satisfy the flawed WMI requirements....
|
|
//
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, MPC::SetInterfaceSecurity_ImpLevel( pWbemEnum, RPC_C_IMP_LEVEL_IMPERSONATE ));
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Create a new WbemContext object.
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, ::CoCreateInstance( CLSID_WbemContext, NULL, CLSCTX_INPROC_SERVER, IID_IWbemContext, (void**)&pWbemContext ));
|
|
|
|
//
|
|
// For the XML to be conformant with the earlier XMLT format,
|
|
// we need VALUE.OBJECTWITHPATH.
|
|
//
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, pWbemContext->SetValue( l_bstrPathLevel, 0, &l_vPathLevel ));
|
|
|
|
//
|
|
// We don't need the system properties that are returned by
|
|
// default. Hence Exclude them from the output.
|
|
//
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, pWbemContext->SetValue( l_bstrExcludeSystemProperties, 0, &l_vExcludeSystemProperties ));
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
// Collate all the instances.
|
|
//
|
|
bstrXML = l_CIM_header;
|
|
while(1)
|
|
{
|
|
CComPtr<IWbemClassObject> pObj;
|
|
CComBSTR bstrXMLCurrent;
|
|
ULONG uReturned;
|
|
bool fProceed;
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, pWbemEnum->Next( WBEM_INFINITE, 1, &pObj, &uReturned ));
|
|
|
|
if(hr == WBEM_S_FALSE || uReturned == 0) break;
|
|
|
|
hrXML = pWbemTextSrc->GetText( 0, pObj, WMI_OBJ_TEXT_WMI_DTD_2_0, pWbemContext, &bstrXMLCurrent );
|
|
if(FAILED(hrXML))
|
|
{
|
|
CComQIPtr<ISupportErrorInfo> sei = pWbemTextSrc;
|
|
|
|
if(sei && SUCCEEDED(sei->InterfaceSupportsErrorInfo( IID_IWbemObjectTextSrc )))
|
|
{
|
|
CComPtr<IErrorInfo> ei;
|
|
|
|
if(SUCCEEDED(GetErrorInfo( 0, &ei )) && ei)
|
|
{
|
|
ei->GetDescription( &m_hcpdcrcCurrentReport->m_bstrDescription );
|
|
}
|
|
}
|
|
|
|
m_hcpdcrcCurrentReport->m_dwErrorCode = hrXML;
|
|
|
|
__MPC_SET_ERROR_AND_EXIT(hr, S_FALSE);
|
|
}
|
|
|
|
// Append the individual instance XMLs
|
|
//
|
|
bstrXML.Append( bstrXMLCurrent );
|
|
}
|
|
bstrXML.Append( l_CIM_trailer );
|
|
|
|
//
|
|
// Load the result into an XML DOM object.
|
|
//
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, ::CoCreateInstance( CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER, IID_IXMLDOMDocument, (void**)&xddDoc ));
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, xddDoc->loadXML( bstrXML, &fSuccessful ));
|
|
if(fSuccessful == VARIANT_FALSE)
|
|
{
|
|
CComQIPtr<ISupportErrorInfo> sei = xddDoc;
|
|
|
|
if(sei && SUCCEEDED(sei->InterfaceSupportsErrorInfo( IID_IXMLDOMDocument )))
|
|
{
|
|
CComPtr<IErrorInfo> ei;
|
|
|
|
if(SUCCEEDED(GetErrorInfo( 0, &ei )))
|
|
{
|
|
ei->GetDescription( &m_hcpdcrcCurrentReport->m_bstrDescription );
|
|
}
|
|
}
|
|
|
|
m_hcpdcrcCurrentReport->m_dwErrorCode = ERROR_BAD_FORMAT;
|
|
|
|
__MPC_SET_ERROR_AND_EXIT(hr, S_FALSE);
|
|
}
|
|
|
|
// __MPC_EXIT_IF_METHOD_FAILS(hr, xddDoc->save( CComVariant( "C:\\dump.xml" ) ));
|
|
|
|
//
|
|
// Return the pointer to the XML document.
|
|
//
|
|
*ppxddDoc = xddDoc.Detach();
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
HRESULT CSAFDataCollection::Distribute( /*[in] */ IXMLDOMDocument* pxddDoc ,
|
|
/*[in/out]*/ QueryResults& qr ,
|
|
/*[in/out]*/ WMIParser::ClusterByClassMap& cluster )
|
|
{
|
|
__HCP_FUNC_ENTRY( "CSAFDataCollection::Distribute" );
|
|
|
|
HRESULT hr;
|
|
MPC::XmlUtil xml( pxddDoc );
|
|
CComPtr<IXMLDOMNode> xdnRoot;
|
|
WMIParser::Snapshot *pwmips = NULL;
|
|
|
|
__MPC_EXIT_IF_ALLOC_FAILS(hr, pwmips, new WMIParser::Snapshot());
|
|
qr.push_back( pwmips );
|
|
|
|
//
|
|
// Quick fix for broken Incident object: force UNICODE encoding.
|
|
//
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, xml.SetVersionAndEncoding( L"1.0", L"unicode" ));
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, xml.GetRoot ( &xdnRoot ));
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, pwmips->put_Node ( xdnRoot ));
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, WMIParser::DistributeOnCluster( cluster, *pwmips ));
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
HRESULT CSAFDataCollection::ComputeDelta( /*[in]*/ QueryResults& qr ,
|
|
/*[in]*/ WMIParser::ClusterByClassMap& cluster ,
|
|
/*[in]*/ WMIHistory::Database::ProvList& lstQueries ,
|
|
/*[in]*/ bool fPersist )
|
|
{
|
|
__HCP_FUNC_ENTRY( "CSAFDataCollection::ComputeDelta" );
|
|
|
|
HRESULT hr;
|
|
WMIHistory::Database::ProvIterConst it;
|
|
|
|
|
|
for(it=lstQueries.begin(); it!=lstQueries.end(); it++)
|
|
{
|
|
WMIHistory::Provider* wmihp = *it;
|
|
WMIHistory::Data* wmihpd_T0;
|
|
WMIHistory::Data* wmihpd_T1;
|
|
WMIHistory::Data* wmihpd_D1;
|
|
CComPtr<IXMLDOMDocument> xddDoc;
|
|
MPC::wstring szNamespace;
|
|
MPC::wstring szClass;
|
|
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, wmihp->get_Namespace( szNamespace ));
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, wmihp->get_Class ( szClass ));
|
|
|
|
|
|
//
|
|
// Collate only the data from current cluster.
|
|
//
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, CollateMachineData( qr, cluster, &szNamespace, &szClass, true, &xddDoc ));
|
|
|
|
|
|
//
|
|
// Save it to a file.
|
|
//
|
|
{
|
|
MPC::XmlUtil xml( xddDoc );
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, wmihp->alloc_Snapshot( xml, wmihpd_T1 ));
|
|
}
|
|
|
|
|
|
//
|
|
// If two snapshots are present, compute the delta.
|
|
//
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, wmihp->get_Snapshot( wmihpd_T0 ));
|
|
if(wmihpd_T0 == NULL)
|
|
{
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, wmihp->insert_Snapshot( wmihpd_T1, fPersist ));
|
|
}
|
|
else
|
|
{
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, wmihp->ComputeDiff( wmihpd_T0, wmihpd_T1, wmihpd_D1 ));
|
|
if(wmihpd_D1)
|
|
{
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, wmihp->insert_Snapshot( wmihpd_D1, fPersist ));
|
|
}
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, wmihp->insert_Snapshot( wmihpd_T1, fPersist ));
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, wmihp->remove_Snapshot( wmihpd_T0, fPersist ));
|
|
}
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
HRESULT CSAFDataCollection::CollateMachineData( /*[in] */ QueryResults& qr ,
|
|
/*[in] */ WMIParser::ClusterByClassMap& cluster ,
|
|
/*[in] */ MPC::wstring* pszNamespace ,
|
|
/*[in] */ MPC::wstring* pszClass ,
|
|
/*[in] */ bool fGenerate ,
|
|
/*[out]*/ IXMLDOMDocument* *ppxddDoc )
|
|
{
|
|
__HCP_FUNC_ENTRY( "CSAFDataCollection::CollateMachineData" );
|
|
|
|
HRESULT hr;
|
|
WMIParser::Snapshot wmips;
|
|
|
|
|
|
*ppxddDoc = NULL;
|
|
CHECK_ABORTED();
|
|
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, wmips.New());
|
|
|
|
|
|
if(qr.begin() != qr.end())
|
|
{
|
|
WMIParser::ClusterByClassIter itCluster;
|
|
|
|
//
|
|
// For each cluster, enumerate all the instances in it and copy to the new snapshot.
|
|
//
|
|
for(itCluster = cluster.begin(); itCluster != cluster.end(); itCluster++)
|
|
{
|
|
MPC::NocaseCompare cmp;
|
|
WMIParser::Instance* inst = (*itCluster).first;
|
|
WMIParser::Cluster& subcluster = (*itCluster).second;
|
|
WMIParser::ClusterByKeyIter itSubBegin;
|
|
WMIParser::ClusterByKeyIter itSubEnd;
|
|
|
|
|
|
//
|
|
// Filter only some classes or namespaces.
|
|
//
|
|
if(pszNamespace)
|
|
{
|
|
MPC::wstring szNamespace;
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, inst->get_Namespace( szNamespace ));
|
|
|
|
//
|
|
// NOTICE: if the namespace is "<UNKNOWN>", then assume a match.
|
|
//
|
|
if(szNamespace != L"<UNKNOWN>")
|
|
{
|
|
if(!cmp( szNamespace, *pszNamespace )) continue;
|
|
}
|
|
}
|
|
if(pszClass)
|
|
{
|
|
MPC::wstring szClass;
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, inst->get_Class( szClass ));
|
|
|
|
if(!cmp( szClass, *pszClass )) continue;
|
|
}
|
|
|
|
|
|
//
|
|
// Copy all the instances into the new document.
|
|
//
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, subcluster.Enum( itSubBegin, itSubEnd ));
|
|
while(itSubBegin != itSubEnd)
|
|
{
|
|
WMIParser::Instance* pwmipiInst;
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, wmips.clone_Instance( (*itSubBegin).first, pwmipiInst ));
|
|
fGenerate = true;
|
|
|
|
CHECK_ABORTED();
|
|
itSubBegin++;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Only return the document if at least one instance is present.
|
|
//
|
|
if(fGenerate)
|
|
{
|
|
CComPtr<IXMLDOMNode> xdnRoot;
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, wmips.get_Node( &xdnRoot ));
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, xdnRoot->get_ownerDocument( ppxddDoc ));
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
HRESULT CSAFDataCollection::CollateMachineDataWithTimestamp( /*[in] */ QueryResults& qr ,
|
|
/*[in] */ WMIParser::ClusterByClassMap& cluster ,
|
|
/*[in] */ MPC::wstring* pszNamespace ,
|
|
/*[in] */ MPC::wstring* pszClass ,
|
|
/*[out]*/ IXMLDOMDocument* *ppxddDoc )
|
|
{
|
|
__HCP_FUNC_ENTRY( "CSAFDataCollection::CollateMachineDataWithTimestamp" );
|
|
|
|
HRESULT hr;
|
|
CComPtr<IXMLDOMDocument> xdd;
|
|
|
|
|
|
*ppxddDoc = NULL;
|
|
CHECK_ABORTED();
|
|
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, CollateMachineData( qr, cluster, NULL, NULL, false, &xdd ));
|
|
if(xdd)
|
|
{
|
|
MPC::XmlUtil xml;
|
|
CComPtr<IXMLDOMNode> xdnNodeSnapshot;
|
|
|
|
|
|
//
|
|
// Create the document.
|
|
//
|
|
{
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, xml.New( TEXT_TAG_DATACOLLECTION ));
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, xml.CreateNode( TEXT_TAG_SNAPSHOT, &xdnNodeSnapshot ));
|
|
}
|
|
|
|
|
|
//
|
|
// Set the date.
|
|
//
|
|
{
|
|
DATE dTimestamp = MPC::GetLocalTime();
|
|
TIME_ZONE_INFORMATION tzi;
|
|
MPC::wstring szValue;
|
|
bool fFound;
|
|
|
|
if(::GetTimeZoneInformation( &tzi ) == TIME_ZONE_ID_DAYLIGHT)
|
|
{
|
|
tzi.Bias += tzi.DaylightBias;
|
|
}
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, MPC::ConvertDateToString( dTimestamp, szValue, /*fGMT*/true, /*fCIM*/true, 0 ));
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, xml.PutAttribute( NULL, TEXT_ATTR_TIMESTAMP, szValue, fFound, xdnNodeSnapshot ));
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, xml.PutAttribute( NULL, TEXT_ATTR_TIMEZONE, (LONG)tzi.Bias, fFound, xdnNodeSnapshot ));
|
|
}
|
|
|
|
|
|
//
|
|
// Insert the CIM tree into the document.
|
|
//
|
|
{
|
|
CComPtr<IXMLDOMNode> xdnNodeToInsert;
|
|
CComPtr<IXMLDOMNode> xdnNodeReplaced;
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, xdd->get_documentElement( (IXMLDOMElement**)&xdnNodeToInsert ));
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, xdnNodeSnapshot->appendChild( xdnNodeToInsert, &xdnNodeReplaced ));
|
|
}
|
|
|
|
//
|
|
// Return the XML blob to the caller.
|
|
//
|
|
{
|
|
CComPtr<IXMLDOMNode> xdnRoot;
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, xml.GetRoot ( &xdnRoot ));
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, xdnRoot->get_ownerDocument( ppxddDoc ));
|
|
}
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
HRESULT CSAFDataCollection::CollateHistory( /*[in] */ WMIHistory::Database& wmihdQuery ,
|
|
/*[in] */ WMIHistory::Database& wmihdFilter ,
|
|
/*[out]*/ IXMLDOMDocument* *ppxddDoc )
|
|
{
|
|
__HCP_FUNC_ENTRY( "CSAFDataCollection::CollateHistory" );
|
|
|
|
typedef std::vector< LONG > SeqVector;
|
|
typedef SeqVector::iterator SeqIter;
|
|
typedef SeqVector::const_iterator SeqIterConst;
|
|
|
|
HRESULT hr;
|
|
QueryResults qr;
|
|
WMIParser::ClusterByClassMap cluster;
|
|
WMIHistory::Database::ProvList prov_lst;
|
|
WMIHistory::Database::ProvIterConst prov_itBegin;
|
|
WMIHistory::Database::ProvIterConst prov_itEnd;
|
|
WMIHistory::Database::ProvIterConst prov_it;
|
|
SeqVector seq_vec;
|
|
SeqIterConst seq_it;
|
|
MPC::XmlUtil xml;
|
|
MPC::wstring szValue;
|
|
bool fFound;
|
|
long lHistory = m_lHistory; // Number of deltas to collect.
|
|
DATE dTimestampCurrent;
|
|
DATE dTimestampNext;
|
|
TIME_ZONE_INFORMATION tzi;
|
|
|
|
|
|
*ppxddDoc = NULL;
|
|
CHECK_ABORTED();
|
|
|
|
|
|
if(::GetTimeZoneInformation( &tzi ) == TIME_ZONE_ID_DAYLIGHT)
|
|
{
|
|
tzi.Bias += tzi.DaylightBias;
|
|
}
|
|
|
|
|
|
//
|
|
// Form the list of providers to collate.
|
|
//
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, wmihdQuery.get_Providers( prov_itBegin, prov_itEnd ));
|
|
for(prov_it=prov_itBegin; prov_it!=prov_itEnd; prov_it++)
|
|
{
|
|
WMIHistory::Provider* wmihp = *prov_it;
|
|
WMIHistory::Provider* wmihpFilter;
|
|
MPC::wstring szNamespace;
|
|
MPC::wstring szClass;
|
|
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, wmihp->get_Namespace ( szNamespace ));
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, wmihp->get_Class ( szClass ));
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, wmihdFilter.find_Provider( NULL, &szNamespace, &szClass, wmihpFilter ));
|
|
|
|
//
|
|
// The namespace/class is known, add it to the list.
|
|
//
|
|
if(wmihpFilter)
|
|
{
|
|
WMIHistory::Provider::DataIterConst itBegin;
|
|
WMIHistory::Provider::DataIterConst itEnd;
|
|
LONG lSequence;
|
|
|
|
//
|
|
// For each delta, extract the sequence info and add it to a list of UNIQUE sequence numbers.
|
|
//
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, wmihp->enum_Data( itBegin, itEnd ));
|
|
while(itBegin != itEnd)
|
|
{
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, (*itBegin++)->get_Sequence( lSequence ));
|
|
|
|
if(std::find( seq_vec.begin(), seq_vec.end(), lSequence ) == seq_vec.end())
|
|
{
|
|
seq_vec.push_back( lSequence );
|
|
}
|
|
}
|
|
|
|
prov_lst.push_back( wmihp );
|
|
}
|
|
}
|
|
|
|
//
|
|
// The list of dates is empty, so no data is available.
|
|
//
|
|
if(seq_vec.begin() == seq_vec.end())
|
|
{
|
|
__MPC_SET_ERROR_AND_EXIT(hr, S_OK);
|
|
}
|
|
|
|
//
|
|
// Sort the dates from the newest to the oldest.
|
|
//
|
|
std::sort< SeqIter >( seq_vec.begin(), seq_vec.end(), std::greater<LONG>() );
|
|
|
|
CHECK_ABORTED();
|
|
|
|
|
|
//
|
|
// Create the document.
|
|
//
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, xml.New( TEXT_TAG_DATACOLLECTION ));
|
|
|
|
|
|
//
|
|
// First of all, collate the snapshots.
|
|
//
|
|
{
|
|
CComPtr<IXMLDOMDocument> xdd;
|
|
CComPtr<IXMLDOMNode> xdnNode;
|
|
CComPtr<IXMLDOMNode> xdnNodeToInsert;
|
|
CComPtr<IXMLDOMNode> xdnNodeReplaced;
|
|
|
|
|
|
//
|
|
// Walk through all the providers and load the snapshots.
|
|
//
|
|
for(prov_it=prov_lst.begin(); prov_it!=prov_lst.end(); prov_it++)
|
|
{
|
|
WMIHistory::Data* wmihpd;
|
|
MPC::XmlUtil xmlData;
|
|
CComPtr<IXMLDOMDocument> xddData;
|
|
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, (*prov_it)->get_Snapshot( wmihpd ));
|
|
if(wmihpd == NULL) continue;
|
|
|
|
|
|
//
|
|
// If it's the first provider we see in this round, create the proper element, "Snapshot".
|
|
//
|
|
// As its date, we pick the latest date in the list of dates. This is because not all the snapshots have the
|
|
// same date, when two snapshots are identical, no delta is created and the new snapshot is not stored.
|
|
// But it's guarantee that, if there's a snapshot, its date is greater than any delta's date.
|
|
//
|
|
if(xdnNode == NULL)
|
|
{
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, wmihpd->get_TimestampT0( dTimestampCurrent ));
|
|
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, xml.CreateNode( TEXT_TAG_SNAPSHOT, &xdnNode ));
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, MPC::ConvertDateToString( dTimestampCurrent, szValue, /*fGMT*/true, /*fCIM*/true, 0 ));
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, xml.PutAttribute( NULL, TEXT_ATTR_TIMESTAMP, szValue, fFound, xdnNode ));
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, xml.PutAttribute( NULL, TEXT_ATTR_TIMEZONE, (LONG)tzi.Bias, fFound, xdnNode ));
|
|
}
|
|
|
|
|
|
//
|
|
// Load the data and distribuite among clusters.
|
|
//
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, wmihpd->LoadCIM ( xmlData ));
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, xmlData.GetDocument( &xddData ));
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, Distribute ( xddData, qr, cluster ));
|
|
}
|
|
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, CollateMachineData( qr, cluster, NULL, NULL, false, &xdd ));
|
|
if(xdd)
|
|
{
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, xdd->get_documentElement( (IXMLDOMElement**)&xdnNodeToInsert ));
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, xdnNode->appendChild( xdnNodeToInsert, &xdnNodeReplaced ));
|
|
}
|
|
|
|
|
|
//
|
|
// Cleanup everything.
|
|
//
|
|
cluster.clear();
|
|
CleanQueryResult( qr );
|
|
}
|
|
|
|
|
|
//
|
|
// Them, for each date, collate all its deltas.
|
|
//
|
|
for(seq_it=seq_vec.begin(); seq_it!=seq_vec.end(); seq_it++)
|
|
{
|
|
CComPtr<IXMLDOMDocument> xdd;
|
|
CComPtr<IXMLDOMNode> xdnNode;
|
|
CComPtr<IXMLDOMNode> xdnNodeToInsert;
|
|
CComPtr<IXMLDOMNode> xdnNodeReplaced;
|
|
|
|
|
|
//
|
|
// Walk through all the providers and load data about the current date.
|
|
//
|
|
for(prov_it=prov_lst.begin(); prov_it!=prov_lst.end(); prov_it++)
|
|
{
|
|
WMIHistory::Data* wmihpd;
|
|
MPC::XmlUtil xmlData;
|
|
CComPtr<IXMLDOMDocument> xddData;
|
|
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, (*prov_it)->get_Sequence( *seq_it, wmihpd ));
|
|
if(wmihpd == NULL ) continue;
|
|
if(wmihpd->IsSnapshot()) continue;
|
|
|
|
|
|
//
|
|
// If it's the first provider we see in this round, create the proper element, "Snapshot" or "Delta".
|
|
//
|
|
if(xdnNode == NULL)
|
|
{
|
|
dTimestampNext = dTimestampCurrent;
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, wmihpd->get_TimestampT0( dTimestampCurrent ));
|
|
|
|
//
|
|
// Check if we have reached the requested number of deltas.
|
|
//
|
|
if(lHistory-- <= 0) break;
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, xml.CreateNode( TEXT_TAG_DELTA, &xdnNode ));
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, MPC::ConvertDateToString( dTimestampCurrent, szValue, /*fGMT*/true, /*fCIM*/true, 0 ));
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, xml.PutAttribute( NULL, TEXT_ATTR_TIMESTAMP_T0, szValue, fFound, xdnNode ));
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, MPC::ConvertDateToString( dTimestampNext, szValue, /*fGMT*/true, /*fCIM*/true, 0 ));
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, xml.PutAttribute( NULL, TEXT_ATTR_TIMESTAMP_T1, szValue, fFound, xdnNode ));
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, xml.PutAttribute( NULL, TEXT_ATTR_TIMEZONE, (LONG)tzi.Bias, fFound, xdnNode ));
|
|
}
|
|
|
|
|
|
//
|
|
// Load the data and distribuite among clusters.
|
|
//
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, wmihpd->LoadCIM ( xmlData ));
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, xmlData.GetDocument( &xddData ));
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, Distribute ( xddData, qr, cluster ));
|
|
}
|
|
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, CollateMachineData( qr, cluster, NULL, NULL, false, &xdd ));
|
|
if(xdd)
|
|
{
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, xdd->get_documentElement( (IXMLDOMElement**)&xdnNodeToInsert ));
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, xdnNode->appendChild( xdnNodeToInsert, &xdnNodeReplaced ));
|
|
}
|
|
|
|
|
|
//
|
|
// Cleanup everything.
|
|
//
|
|
cluster.clear();
|
|
CleanQueryResult( qr );
|
|
}
|
|
|
|
|
|
//
|
|
// Return the XML blob to the caller.
|
|
//
|
|
{
|
|
CComPtr<IXMLDOMNode> xdnRoot;
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, xml.GetRoot( &xdnRoot ));
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, xdnRoot->get_ownerDocument( ppxddDoc ));
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
//
|
|
// Make sure to delete the temporary WMIParser:Snapshot objects.
|
|
//
|
|
CleanQueryResult( qr );
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
//////////////////////////
|
|
// //
|
|
// Event Firing Methods //
|
|
// //
|
|
//////////////////////////
|
|
|
|
HRESULT CSAFDataCollection::Fire_onStatusChange( ISAFDataCollection* hcpdc, tagDC_STATUS dsStatus )
|
|
{
|
|
CComVariant pvars[2];
|
|
|
|
|
|
//
|
|
// Only this part should be inside a critical section, otherwise deadlocks could occur.
|
|
//
|
|
{
|
|
MPC::SmartLock<_ThreadModel> lock( this );
|
|
|
|
//
|
|
// Disable events if the "onComplete" event has already been sent.
|
|
//
|
|
if(m_fCompleted) return S_OK;
|
|
}
|
|
|
|
pvars[1] = hcpdc;
|
|
pvars[0] = dsStatus;
|
|
|
|
return FireAsync_Generic( DISPID_SAF_DCE__ONSTATUSCHANGE, pvars, ARRAYSIZE( pvars ), m_sink_onStatusChange );
|
|
}
|
|
|
|
HRESULT CSAFDataCollection::Fire_onProgress( ISAFDataCollection* hcpdc, LONG lDone, LONG lTotal )
|
|
{
|
|
CComVariant pvars[3];
|
|
|
|
|
|
//
|
|
// Only this part should be inside a critical section, otherwise deadlocks could occur.
|
|
//
|
|
{
|
|
MPC::SmartLock<_ThreadModel> lock( this );
|
|
|
|
//
|
|
// Disable events if the "onComplete" event has already been sent.
|
|
//
|
|
if(m_fCompleted) return S_OK;
|
|
|
|
m_lPercent = lTotal ? (lDone * 100.0 / lTotal) : 0;
|
|
}
|
|
|
|
|
|
pvars[2] = hcpdc;
|
|
pvars[1] = lDone;
|
|
pvars[0] = lTotal;
|
|
|
|
return FireAsync_Generic( DISPID_SAF_DCE__ONPROGRESS, pvars, ARRAYSIZE( pvars ), m_sink_onProgress );
|
|
}
|
|
|
|
HRESULT CSAFDataCollection::Fire_onComplete( ISAFDataCollection* hcpdc, HRESULT hrRes )
|
|
{
|
|
CComVariant pvars[2];
|
|
|
|
|
|
//
|
|
// Only this part should be inside a critical section, otherwise deadlocks could occur.
|
|
//
|
|
{
|
|
MPC::SmartLock<_ThreadModel> lock( this );
|
|
|
|
//
|
|
// Disable events if the "onComplete" event has already been sent.
|
|
//
|
|
if(m_fCompleted) return S_OK;
|
|
|
|
m_fCompleted = true;
|
|
}
|
|
|
|
|
|
pvars[1] = hcpdc;
|
|
pvars[0] = hrRes;
|
|
|
|
return FireAsync_Generic( DISPID_SAF_DCE__ONCOMPLETE, pvars, ARRAYSIZE( pvars ), m_sink_onComplete );
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
/////////////////////
|
|
// //
|
|
// Utility Methods //
|
|
// //
|
|
/////////////////////
|
|
|
|
HRESULT CSAFDataCollection::CanModifyProperties()
|
|
{
|
|
__HCP_FUNC_ENTRY( "CSAFDataCollection::CanModifyProperties" );
|
|
|
|
HRESULT hr = E_ACCESSDENIED;
|
|
|
|
|
|
if(m_fWorking == false ||
|
|
m_fCompleted == true )
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
HRESULT CSAFDataCollection::IsCollectionAborted()
|
|
{
|
|
__HCP_FUNC_ENTRY( "CSAFDataCollection::IsCollectionAborted" );
|
|
|
|
HRESULT hr;
|
|
|
|
//
|
|
// We not only check for explicit abortion, but also for low memory situations.
|
|
// Our code is almost safe, but we have seen that other parts of the system
|
|
// tend to crash on no-memory scenarios.
|
|
//
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, MPC::FailOnLowMemory( SAFETY_MARGIN__MEMORY ));
|
|
|
|
if(Thread_IsAborted() == true)
|
|
{
|
|
__MPC_SET_ERROR_AND_EXIT(hr, E_ABORT);
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
////////////////////////////////////////////
|
|
// //
|
|
// Internal Property Manipulation Methods //
|
|
// //
|
|
////////////////////////////////////////////
|
|
|
|
HRESULT CSAFDataCollection::put_Status( /*[in]*/ DC_STATUS newVal )
|
|
{
|
|
__HCP_FUNC_ENTRY( "CSAFDataCollection::put_Status" );
|
|
|
|
HRESULT hr = try_Status( (DC_STATUS)-1, newVal );
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
HRESULT CSAFDataCollection::try_Status( /*[in]*/ DC_STATUS preVal ,
|
|
/*[in]*/ DC_STATUS postVal )
|
|
{
|
|
__HCP_FUNC_ENTRY( "CSAFDataCollection::try_Status" );
|
|
|
|
HRESULT hr;
|
|
bool fChanged = false;
|
|
DC_STATUS dsStatus;
|
|
MPC::SmartLock<_ThreadModel> lock( this );
|
|
|
|
|
|
if(preVal == m_dsStatus ||
|
|
preVal == -1 )
|
|
{
|
|
fChanged = (m_dsStatus != postVal);
|
|
m_dsStatus = postVal;
|
|
|
|
dsStatus = m_dsStatus;
|
|
|
|
//
|
|
// Clean error at start of data collection.
|
|
//
|
|
switch(m_dsStatus)
|
|
{
|
|
case DC_COLLECTING:
|
|
case DC_COMPARING:
|
|
m_dwErrorCode = 0;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
__MPC_SET_ERROR_AND_EXIT(hr, S_FALSE);
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
lock = NULL; // Release the lock before firing the event.
|
|
|
|
//
|
|
// Important, leave these calls outside Locked Sections!!
|
|
//
|
|
if(SUCCEEDED(hr) && fChanged)
|
|
{
|
|
Fire_onStatusChange( this, dsStatus );
|
|
}
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
HRESULT CSAFDataCollection::put_ErrorCode( /*[in]*/ DWORD newVal )
|
|
{
|
|
__HCP_FUNC_ENTRY( "CSAFDataCollection::put_ErrorCode" );
|
|
|
|
HRESULT hr;
|
|
MPC::SmartLock<_ThreadModel> lock( this );
|
|
|
|
|
|
m_dwErrorCode = newVal;
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
////////////////
|
|
// //
|
|
// Properties //
|
|
// //
|
|
////////////////
|
|
|
|
|
|
STDMETHODIMP CSAFDataCollection::get_Status( /*[out]*/ DC_STATUS *pVal )
|
|
{
|
|
__HCP_BEGIN_PROPERTY_GET2("CSAFDataCollection::get_Status",hr,pVal,m_dsStatus);
|
|
|
|
__HCP_END_PROPERTY(hr);
|
|
}
|
|
|
|
STDMETHODIMP CSAFDataCollection::get_PercentDone( /*[out]*/ long *pVal )
|
|
{
|
|
__HCP_BEGIN_PROPERTY_GET2("CSAFDataCollection::get_PercentDone",hr,pVal,m_lPercent);
|
|
|
|
__HCP_END_PROPERTY(hr);
|
|
}
|
|
|
|
STDMETHODIMP CSAFDataCollection::get_ErrorCode( /*[out]*/ long *pVal )
|
|
{
|
|
__HCP_BEGIN_PROPERTY_GET2("CSAFDataCollection::get_ErrorCode",hr,pVal,(long)m_dwErrorCode);
|
|
|
|
__HCP_END_PROPERTY(hr);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
STDMETHODIMP CSAFDataCollection::get_MachineData_DataSpec( /*[out]*/ BSTR *pVal )
|
|
{
|
|
MPC::SmartLock<_ThreadModel> lock( this );
|
|
|
|
return MPC::GetBSTR( m_bstrMachineData, pVal );
|
|
}
|
|
|
|
STDMETHODIMP CSAFDataCollection::put_MachineData_DataSpec( /*[in]*/ BSTR newVal )
|
|
{
|
|
__HCP_BEGIN_PROPERTY_PUT("CSAFDataCollection::put_MachineData_DataSpec",hr);
|
|
|
|
CHECK_MODIFY();
|
|
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, MPC::PutBSTR( m_bstrMachineData, newVal ));
|
|
|
|
|
|
__HCP_END_PROPERTY(hr);
|
|
}
|
|
|
|
|
|
STDMETHODIMP CSAFDataCollection::get_History_DataSpec( /*[out]*/ BSTR *pVal )
|
|
{
|
|
MPC::SmartLock<_ThreadModel> lock( this );
|
|
|
|
return MPC::GetBSTR( m_bstrHistory, pVal );
|
|
}
|
|
|
|
STDMETHODIMP CSAFDataCollection::put_History_DataSpec( /*[in]*/ BSTR newVal )
|
|
{
|
|
__HCP_BEGIN_PROPERTY_PUT("CSAFDataCollection::put_History_DataSpec",hr);
|
|
|
|
CHECK_MODIFY();
|
|
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, MPC::PutBSTR( m_bstrHistory, newVal ));
|
|
|
|
|
|
__HCP_END_PROPERTY(hr);
|
|
}
|
|
|
|
STDMETHODIMP CSAFDataCollection::get_History_MaxDeltas( /*[out]*/ long *pVal )
|
|
{
|
|
__HCP_BEGIN_PROPERTY_GET2("CSAFDataCollection::get_History_MaxDeltas",hr,pVal,m_lHistory);
|
|
|
|
__HCP_END_PROPERTY(hr);
|
|
}
|
|
|
|
STDMETHODIMP CSAFDataCollection::put_History_MaxDeltas( /*[in]*/ long newVal )
|
|
{
|
|
__HCP_BEGIN_PROPERTY_PUT("CSAFDataCollection::put_History_MaxDeltas",hr);
|
|
|
|
//
|
|
// Check validity range.
|
|
//
|
|
if(newVal < 0 ||
|
|
newVal > WMIHISTORY_MAX_NUMBER_OF_DELTAS )
|
|
{
|
|
__MPC_SET_ERROR_AND_EXIT(hr, E_INVALIDARG);
|
|
}
|
|
|
|
|
|
m_lHistory = newVal;
|
|
|
|
|
|
__HCP_END_PROPERTY(hr);
|
|
}
|
|
|
|
STDMETHODIMP CSAFDataCollection::get_History_MaxSupportedDeltas( /*[out]*/ long *pVal )
|
|
{
|
|
__HCP_BEGIN_PROPERTY_GET2("CSAFDataCollection::get_History_MaxSupportedDeltas",hr,pVal,WMIHISTORY_MAX_NUMBER_OF_DELTAS);
|
|
|
|
__HCP_END_PROPERTY(hr);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
STDMETHODIMP CSAFDataCollection::put_onStatusChange( /*[in]*/ IDispatch* function )
|
|
{
|
|
__HCP_FUNC_ENTRY( "CSAFDataCollection::put_onStatusChange" );
|
|
|
|
m_sink_onStatusChange = function;
|
|
|
|
__HCP_FUNC_EXIT(S_OK);
|
|
}
|
|
|
|
STDMETHODIMP CSAFDataCollection::put_onProgress( /*[in]*/ IDispatch* function )
|
|
{
|
|
__HCP_FUNC_ENTRY( "CSAFDataCollection::put_onProgress" );
|
|
|
|
m_sink_onProgress = function;
|
|
|
|
__HCP_FUNC_EXIT(S_OK);
|
|
}
|
|
|
|
STDMETHODIMP CSAFDataCollection::put_onComplete( /*[in]*/ IDispatch* function )
|
|
{
|
|
__HCP_FUNC_ENTRY( "CSAFDataCollection::put_onComplete" );
|
|
|
|
m_sink_onComplete = function;
|
|
|
|
__HCP_FUNC_EXIT(S_OK);
|
|
}
|
|
|
|
STDMETHODIMP CSAFDataCollection::get_Reports( /*[out]*/ IPCHCollection* *ppC )
|
|
{
|
|
__HCP_FUNC_ENTRY( "CSAFDataCollection::get_Reports" );
|
|
|
|
HRESULT hr;
|
|
IterConst it;
|
|
CComPtr<CPCHCollection> pColl;
|
|
MPC::SmartLock<_ThreadModel> lock( this );
|
|
|
|
__MPC_PARAMCHECK_BEGIN(hr)
|
|
__MPC_PARAMCHECK_POINTER_AND_SET(ppC,NULL);
|
|
__MPC_PARAMCHECK_END();
|
|
|
|
CHECK_MODIFY();
|
|
|
|
|
|
//
|
|
// Create the Enumerator and fill it with jobs.
|
|
//
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, MPC::CreateInstance( &pColl ));
|
|
|
|
for(it = m_lstReports.begin(); it != m_lstReports.end(); it++)
|
|
{
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, pColl->AddItem( *it ));
|
|
}
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, pColl.QueryInterface( ppC ));
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
/////////////
|
|
// Methods //
|
|
/////////////
|
|
|
|
STDMETHODIMP CSAFDataCollection::ExecuteSync()
|
|
{
|
|
__HCP_FUNC_ENTRY( "CSAFDataCollection::ExecuteSync" );
|
|
|
|
HRESULT hr;
|
|
CComPtr<CSAFDataCollectionEvents> hcpdceEvent;
|
|
CComPtr<ISAFDataCollection> hcpdc;
|
|
|
|
|
|
//
|
|
// Create the Wait object.
|
|
//
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, MPC::CreateInstance( &hcpdceEvent ));
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, QueryInterface( IID_ISAFDataCollection, (void**)&hcpdc ));
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, hcpdceEvent->WaitForCompletion( hcpdc ));
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
STDMETHODIMP CSAFDataCollection::ExecuteAsync()
|
|
{
|
|
__HCP_FUNC_ENTRY( "CSAFDataCollection::ExecuteAsync" );
|
|
|
|
HRESULT hr;
|
|
MPC::SmartLock<_ThreadModel> lock( this );
|
|
|
|
|
|
CHECK_MODIFY();
|
|
|
|
|
|
//
|
|
// At least a data spec file should be supplied.
|
|
//
|
|
if(m_bstrMachineData.Length() == 0 &&
|
|
m_bstrHistory .Length() == 0 )
|
|
{
|
|
__MPC_SET_ERROR_AND_EXIT(hr, E_INVALIDARG);
|
|
}
|
|
|
|
|
|
//
|
|
// Release the lock on current object, otherwise a deadlock could occur.
|
|
//
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, m_imp.Initialize());
|
|
|
|
//
|
|
// Let's go into read-only mode.
|
|
//
|
|
StartOperations();
|
|
|
|
lock = NULL;
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, Thread_Start( this, ExecLoopCollect, NULL ));
|
|
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
STDMETHODIMP CSAFDataCollection::Abort()
|
|
{
|
|
__HCP_FUNC_ENTRY( "CSAFDataCollection::Abort" );
|
|
|
|
MPC::SmartLock<_ThreadModel> lock( this );
|
|
|
|
|
|
if(FAILED(CanModifyProperties()))
|
|
{
|
|
Thread_Abort();
|
|
}
|
|
|
|
|
|
__HCP_FUNC_EXIT(S_OK);
|
|
}
|
|
|
|
|
|
STDMETHODIMP CSAFDataCollection::MachineData_GetStream( /*[in]*/ IUnknown* *stream )
|
|
{
|
|
__HCP_FUNC_ENTRY( "CSAFDataCollection::MachineData_GetStream" );
|
|
|
|
HRESULT hr;
|
|
|
|
|
|
__MPC_PARAMCHECK_BEGIN(hr)
|
|
__MPC_PARAMCHECK_POINTER_AND_SET(stream,NULL);
|
|
__MPC_PARAMCHECK_END();
|
|
|
|
if(m_streamMachineData)
|
|
{
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, m_streamMachineData.QueryInterface( stream ));
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
STDMETHODIMP CSAFDataCollection::History_GetStream( /*[in]*/ IUnknown* *stream )
|
|
{
|
|
__HCP_FUNC_ENTRY( "CSAFDataCollection::History_GetStream" );
|
|
|
|
HRESULT hr;
|
|
|
|
|
|
__MPC_PARAMCHECK_BEGIN(hr)
|
|
__MPC_PARAMCHECK_POINTER_AND_SET(stream,NULL);
|
|
__MPC_PARAMCHECK_END();
|
|
|
|
|
|
if(m_streamHistory)
|
|
{
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, m_streamHistory.QueryInterface( stream ));
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
STDMETHODIMP CSAFDataCollection::CompareSnapshots( /*[in] */ BSTR bstrFilenameT0 ,
|
|
/*[in] */ BSTR bstrFilenameT1 ,
|
|
/*[in] */ BSTR bstrFilenameDiff )
|
|
{
|
|
__HCP_FUNC_ENTRY( "CSAFDataCollection::CompareSnapshots" );
|
|
|
|
HRESULT hr;
|
|
MPC::SmartLock<_ThreadModel> lock( this );
|
|
|
|
|
|
__MPC_PARAMCHECK_BEGIN(hr)
|
|
__MPC_PARAMCHECK_STRING_NOT_EMPTY(bstrFilenameT0);
|
|
__MPC_PARAMCHECK_STRING_NOT_EMPTY(bstrFilenameT1);
|
|
__MPC_PARAMCHECK_STRING_NOT_EMPTY(bstrFilenameDiff);
|
|
__MPC_PARAMCHECK_END();
|
|
|
|
CHECK_MODIFY();
|
|
|
|
|
|
m_bstrFilenameT0 = bstrFilenameT0;
|
|
m_bstrFilenameT1 = bstrFilenameT1;
|
|
m_bstrFilenameDiff = bstrFilenameDiff;
|
|
|
|
|
|
//
|
|
// Release the lock on current object, otherwise a deadlock could occur.
|
|
//
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, m_imp.Initialize());
|
|
|
|
//
|
|
// Let's go into read-only mode.
|
|
//
|
|
StartOperations();
|
|
|
|
lock = NULL;
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, Thread_Start( this, ExecLoopCompare, NULL ));
|
|
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
HRESULT CSAFDataCollection::ExecScheduledCollection()
|
|
{
|
|
__HCP_FUNC_ENTRY( "CSAFDataCollection::ExecScheduledCollection" );
|
|
|
|
HRESULT hr;
|
|
QueryResults qr;
|
|
WMIParser::ClusterByClassMap cluster;
|
|
WMIHistory::Database wmihd;
|
|
WMIHistory::Database::ProvList lstQueries;
|
|
HANDLE hThread;
|
|
int iPriority;
|
|
|
|
hThread = ::GetCurrentThread();
|
|
iPriority = ::GetThreadPriority( hThread );
|
|
|
|
::SetThreadPriority( hThread, THREAD_PRIORITY_LOWEST );
|
|
|
|
|
|
//
|
|
// Try to lock the database and load the data spec file.
|
|
//
|
|
while(1)
|
|
{
|
|
if(SUCCEEDED(hr = wmihd.Init( DATASPEC_LOCATION, DATASPEC_CONFIG )))
|
|
{
|
|
break;
|
|
}
|
|
|
|
if(hr != HRESULT_FROM_WIN32( WAIT_TIMEOUT ))
|
|
{
|
|
__MPC_FUNC_LEAVE;
|
|
}
|
|
}
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, wmihd.Load());
|
|
|
|
//
|
|
// Check if enough time has past between two data collections.
|
|
//
|
|
{
|
|
SYSTEMTIME stNow;
|
|
SYSTEMTIME stLatest;
|
|
|
|
|
|
::GetLocalTime ( &stNow );
|
|
::VariantTimeToSystemTime( wmihd.LastTime(), &stLatest );
|
|
|
|
|
|
if(stNow.wYear == stLatest.wYear &&
|
|
stNow.wMonth == stLatest.wMonth &&
|
|
stNow.wDay == stLatest.wDay )
|
|
{
|
|
__MPC_SET_ERROR_AND_EXIT(hr, S_FALSE);
|
|
}
|
|
}
|
|
|
|
m_fScheduled = true;
|
|
|
|
//
|
|
// Filter and count the queries.
|
|
//
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, FilterDataSpec( wmihd, NULL, lstQueries ));
|
|
|
|
//
|
|
// Collect data from WMI.
|
|
//
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, ExecDataSpec( qr, cluster, lstQueries, false ));
|
|
|
|
|
|
//
|
|
// Compute deltas.
|
|
//
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, ComputeDelta( qr, cluster, lstQueries, true ));
|
|
|
|
//
|
|
// Persiste the changes to the database.
|
|
//
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, wmihd.Save());
|
|
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
CleanQueryResult( qr );
|
|
|
|
::SetThreadPriority( hThread, iPriority );
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|