|
|
/******************************************************************************
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); }
|