Leaked source code of windows server 2003
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.
 
 
 
 
 
 

580 lines
16 KiB

/******************************************************************************
Copyright (c) 1999 Microsoft Corporation
Module Name:
SystemMonitor.cpp
Abstract:
This file contains the implementation of the CPCHSystemMonitor class,
which implements the data collection functionality.
Revision History:
Davide Massarenti (Dmassare) 08/25/99
created
******************************************************************************/
#include "stdafx.h"
#include <initguid.h>
#include <mstask.h> // for task scheduler apis
#include <msterr.h>
/////////////////////////////////////////////////////////////////////////////
static const ULONG INITIAL_RESCHEDULE_TIME = 10 * 60; // (10 minutes)
static const ULONG DATACOLLECTION_RESCHEDULE_TIME = 6 * 60 * 60; // (6 hours)
static const ULONG DATACOLLECTION_IDLE_TIME = 5; // (5 minutes)
static const ULONG SECONDS_IN_A_DAY = 24 * 60 * 60;
static const ULONG SECONDS_IN_A_MINUTE = 60;
static const ULONG MINUTES_IN_A_DAY = 24 * 60;
/////////////////////////////////////////////////////////////////////////////
static HRESULT Exec( LPCWSTR szExec )
{
MPC::wstring strCmdLine( szExec ); MPC::SubstituteEnvVariables( strCmdLine );
return MPC::ExecuteCommand( strCmdLine );
}
/////////////////////////////////////////////////////////////////////////////
CPCHSystemMonitor::CPCHSystemMonitor()
{
__HCP_FUNC_ENTRY( "CPCHSystemMonitor::CPCHSystemMonitor" );
m_fLoadCache = false; // bool m_fLoadCache;
m_fScanBatch = true; // bool m_fScanBatch;
m_fDataCollection = false; // bool m_fDataCollection;
(void)MPC::_MPC_Module.RegisterCallback( this, (void (CPCHSystemMonitor::*)())Shutdown );
}
CPCHSystemMonitor::~CPCHSystemMonitor()
{
MPC::_MPC_Module.UnregisterCallback( this );
Shutdown();
}
////////////////////
CPCHSystemMonitor* CPCHSystemMonitor::s_GLOBAL( NULL );
HRESULT CPCHSystemMonitor::InitializeSystem()
{
if(s_GLOBAL == NULL)
{
s_GLOBAL = new CPCHSystemMonitor;
}
return s_GLOBAL ? S_OK : E_OUTOFMEMORY;
}
void CPCHSystemMonitor::FinalizeSystem()
{
if(s_GLOBAL)
{
delete s_GLOBAL; s_GLOBAL = NULL;
}
}
////////////////////
void CPCHSystemMonitor::Shutdown()
{
Thread_Wait();
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
HRESULT CPCHSystemMonitor::EnsureStarted()
{
__HCP_FUNC_ENTRY( "CPCHSystemMonitor::EnsureStarted" );
HRESULT hr;
if(Thread_IsRunning() == false &&
Thread_IsAborted() == false )
{
__MPC_EXIT_IF_METHOD_FAILS(hr, Thread_Start( this, Run, NULL ));
}
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr);
}
HRESULT CPCHSystemMonitor::Run()
{
__HCP_FUNC_ENTRY( "CPCHSystemMonitor::Run" );
const DWORD s_dwNotify = FILE_NOTIFY_CHANGE_FILE_NAME |
FILE_NOTIFY_CHANGE_DIR_NAME |
FILE_NOTIFY_CHANGE_ATTRIBUTES |
FILE_NOTIFY_CHANGE_SIZE |
FILE_NOTIFY_CHANGE_CREATION;
HRESULT hr;
MPC::wstring strBatch( HC_ROOT_HELPSVC_BATCH ); MPC::SubstituteEnvVariables( strBatch );
HANDLE hBatchNotification = INVALID_HANDLE_VALUE;
DWORD dwTimeout = INFINITE;
MPC::SmartLock<_ThreadModel> lock( this );
::SetThreadPriority( ::GetCurrentThread(), THREAD_PRIORITY_LOWEST ); ::Sleep( 0 ); // Yield processor...
////
//// Don't touch task scheduler, it brings in too many things...
////
//// //
//// // Move forward the scheduled data collection by at least 10 minutes.
//// // Task scheduler is available only on normal boots.
//// //
//// if(::GetSystemMetrics( SM_CLEANBOOT ) == 0)
//// {
//// __MPC_EXIT_IF_METHOD_FAILS(hr, TaskScheduler_Add( true ));
//// }
hBatchNotification = ::FindFirstChangeNotificationW( strBatch.c_str(), TRUE, s_dwNotify );
while(Thread_IsAborted() == false)
{
DWORD dwRes;
lock = NULL;
__MPC_EXIT_IF_METHOD_FAILS(hr, RunLoop());
lock = this;
//
// Done, for now...
//
lock = NULL;
dwRes = Thread_WaitForEvents( hBatchNotification == INVALID_HANDLE_VALUE ? NULL : hBatchNotification, dwTimeout );
lock = this;
switch(dwRes)
{
case WAIT_OBJECT_0 :
case WAIT_ABANDONED_0:
break;
case WAIT_OBJECT_0 + 1:
case WAIT_ABANDONED_0 + 1:
::FindNextChangeNotification( hBatchNotification );
dwTimeout = 1*1000; // Don't scan immediately, wait some time.
break;
case WAIT_TIMEOUT:
dwTimeout = INFINITE;
m_fScanBatch = true;
break;
case WAIT_FAILED:
__MPC_SET_WIN32_ERROR_AND_EXIT(hr, ::GetLastError());
}
}
hr = S_OK;
__HCP_FUNC_CLEANUP;
if(hBatchNotification != INVALID_HANDLE_VALUE)
{
::FindCloseChangeNotification( hBatchNotification );
}
Thread_Abort (); // To tell the MPC:Thread object to close the worker thread...
Thread_Release(); // To tell the MPC:Thread object to clean up...
__HCP_FUNC_EXIT(hr);
}
HRESULT CPCHSystemMonitor::RunLoop()
{
__HCP_FUNC_ENTRY( "CPCHSystemMonitor::RunLoop" );
HRESULT hr;
////////////////////////////////////////////////////////////////////////////////
//
// Batch processing for the other update packages.
//
if(m_fScanBatch)
{
CComPtr<CPCHSetOfHelpTopics> sht;
m_fScanBatch = false;
__MPC_EXIT_IF_METHOD_FAILS(hr, MPC::CreateInstance( &sht ));
__MPC_EXIT_IF_METHOD_FAILS(hr, sht->ScanBatch());
}
////////////////////////////////////////////////////////////////////////////////
//
// Load the cache for active SKUs.
//
if(m_fLoadCache)
{
Taxonomy::LockingHandle handle;
Taxonomy::InstalledInstanceIterConst itBegin;
Taxonomy::InstalledInstanceIterConst itEnd;
Taxonomy::InstalledInstanceIterConst it;
m_fLoadCache = false;
//
// Get the list of SKU installed on the machine.
//
__MPC_EXIT_IF_METHOD_FAILS(hr, Taxonomy::InstalledInstanceStore::s_GLOBAL->GrabControl( handle ));
__MPC_EXIT_IF_METHOD_FAILS(hr, Taxonomy::InstalledInstanceStore::s_GLOBAL->SKU_GetList( itBegin, itEnd ));
//
// Enumerate all of the SKUs, creating the index.
//
for(it = itBegin; it != itEnd; it++)
{
__MPC_EXIT_IF_METHOD_FAILS(hr, Taxonomy::Cache::s_GLOBAL->LoadIfMarked( it->m_inst.m_ths ));
}
}
if(m_fDataCollection)
{
CComPtr<CSAFDataCollection> pdc;
m_fDataCollection = false;
__MPC_EXIT_IF_METHOD_FAILS(hr, MPC::CreateInstance( &pdc ));
__MPC_EXIT_IF_METHOD_FAILS(hr, pdc->ExecScheduledCollection());
__MPC_EXIT_IF_METHOD_FAILS(hr, TaskScheduler_Add( false ));
}
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr);
}
////////////////////////////////////////////////////////////////////////////////
HRESULT CPCHSystemMonitor::LoadCache()
{
__HCP_FUNC_ENTRY( "CPCHSystemMonitor::LoadCache" );
HRESULT hr;
MPC::SmartLock<_ThreadModel> lock( this );
__MPC_EXIT_IF_METHOD_FAILS(hr, EnsureStarted());
m_fLoadCache = true;
Thread_Signal();
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr);
}
HRESULT CPCHSystemMonitor::TriggerDataCollection( /*[in]*/ bool fStart )
{
__HCP_FUNC_ENTRY( "CPCHSystemMonitor::TriggerDataCollection" );
HRESULT hr;
MPC::SmartLock<_ThreadModel> lock( this );
if(fStart)
{
__MPC_EXIT_IF_METHOD_FAILS(hr, EnsureStarted());
m_fDataCollection = true;
Thread_Signal();
}
else
{
m_fDataCollection = false;
Thread_Signal();
}
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr);
}
/////////////////////////////////////////////////////////////////////////////
HRESULT CPCHSystemMonitor::TaskScheduler_Add( /*[in]*/ bool fAfterBoot )
{
MPC::wstring strDate;
if(SUCCEEDED(MPC::ConvertDateToString( MPC::GetLocalTime(), strDate, /*fGMT*/false, /*fCIM*/true, 0 )))
{
static const WCHAR s_szRoot [] = HC_REGISTRY_PCHSVC;
static const WCHAR s_szDataCollection[] = L"DataCollection";
(void)MPC::RegKey_Value_Write( strDate, s_szRoot, s_szDataCollection );
}
return S_OK;
}
HRESULT CPCHSystemMonitor::TaskScheduler_Remove()
{
return S_OK;
}
////HRESULT CPCHSystemMonitor::TaskScheduler_Add( /*[in]*/ bool fAfterBoot )
////{
//// __HCP_FUNC_ENTRY( "CPCHSystemMonitor::TaskScheduler_Add" );
////
//// HRESULT hr;
//// CComPtr<ITaskScheduler> pTaskScheduler;
//// CComPtr<ITask> pTask;
//// CComPtr<IUnknown> pTaskUnknown;
//// CComPtr<IScheduledWorkItem> pScheduledWorkItem;
//// bool fTaskExists = false;
////
//// WCHAR rgFileName[MAX_PATH];
//// CComBSTR bstrTaskName;
//// CComBSTR bstrComments;
////
//// ULONG ulTime = fAfterBoot ? INITIAL_RESCHEDULE_TIME : DATACOLLECTION_RESCHEDULE_TIME;
//// WORD wIdle = DATACOLLECTION_IDLE_TIME;
////
//// ////////////////////////////////////////
////
//// //
//// // Get our complete filename -- needed to create a task in the task scheduler.
//// //
//// __MPC_EXIT_IF_CALL_RETURNS_ZERO(hr, ::GetModuleFileNameW( NULL, rgFileName, MAX_PATH ));
////
////
//// __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::LocalizeString( IDS_HELPSVC_TASKNAME , bstrTaskName ));
//// __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::LocalizeString( IDS_HELPSVC_TASKCOMMENT, bstrComments ));
////
//// //
//// // First create the task scheduler.
//// //
//// __MPC_EXIT_IF_METHOD_FAILS(hr, ::CoCreateInstance( CLSID_CTaskScheduler, NULL, CLSCTX_INPROC_SERVER, IID_ITaskScheduler, (void**)&pTaskScheduler ));
////
////
//// //
//// // See if the task already exists in the task scheduler
//// //
//// if(SUCCEEDED(pTaskScheduler->Activate( bstrTaskName, IID_ITask, &pTaskUnknown )))
//// {
//// fTaskExists = true;
////
//// __MPC_EXIT_IF_METHOD_FAILS(hr, pTaskUnknown->QueryInterface( IID_ITask, (void **)&pTask ));
//// }
//// else
//// {
//// //
//// // Create a new task and set its app name and parameters.
//// //
//// if(FAILED(hr = pTaskScheduler->NewWorkItem( bstrTaskName, CLSID_CTask, IID_ITask, (IUnknown**)&pTask )))
//// {
//// if(hr != ERROR_FILE_EXISTS)
//// {
//// __MPC_TRACE_HRESULT(hr);
//// __MPC_FUNC_LEAVE;
//// }
//// }
//// }
////
//// __MPC_EXIT_IF_METHOD_FAILS(hr, pTask->QueryInterface( IID_IScheduledWorkItem, (void **)&pScheduledWorkItem ));
////
//// //
//// // Run under SYSTEM.
//// //
//// __MPC_EXIT_IF_METHOD_FAILS(hr, pScheduledWorkItem->SetAccountInformation( L"", NULL ));
////
//// __MPC_EXIT_IF_METHOD_FAILS(hr, pTask->SetApplicationName( CComBSTR( rgFileName ) ));
//// __MPC_EXIT_IF_METHOD_FAILS(hr, pTask->SetParameters ( CComBSTR( L"-collect" ) ));
////
//// // Set the comment, so we know how this job go there.
//// __MPC_EXIT_IF_METHOD_FAILS(hr, pScheduledWorkItem->SetComment( bstrComments ));
//// __MPC_EXIT_IF_METHOD_FAILS(hr, pScheduledWorkItem->SetFlags ( 0 ));
////
////
////
////
//// // Now, fill in the trigger as necessary.
//// {
//// CComPtr<ITaskTrigger> pTaskTrigger;
//// SYSTEMTIME stNow;
//// DOUBLE dblNextScheduledTime;
//// TASK_TRIGGER ttTaskTrig;
////
////
//// ::ZeroMemory( &ttTaskTrig, sizeof(ttTaskTrig) );
//// ttTaskTrig.cbTriggerSize = sizeof(ttTaskTrig);
////
////
//// if(fTaskExists)
//// {
//// __MPC_EXIT_IF_METHOD_FAILS(hr, pScheduledWorkItem->GetTrigger( 0, &pTaskTrigger ));
//// __MPC_EXIT_IF_METHOD_FAILS(hr, pTaskTrigger ->GetTrigger( &ttTaskTrig ));
//// }
//// else
//// {
//// WORD wTrigNumber;
////
//// __MPC_EXIT_IF_METHOD_FAILS(hr, pScheduledWorkItem->CreateTrigger( &wTrigNumber, &pTaskTrigger ));
//// }
////
////
//// //
//// // Calculate the exact time of next activation.
//// //
//// ::GetLocalTime ( &stNow );
//// ::SystemTimeToVariantTime( &stNow, &dblNextScheduledTime );
////
//// dblNextScheduledTime += (double)ulTime / SECONDS_IN_A_DAY;
//// ::VariantTimeToSystemTime( dblNextScheduledTime, &stNow );
////
////
//// ttTaskTrig.wBeginYear = stNow.wYear;
//// ttTaskTrig.wBeginMonth = stNow.wMonth;
//// ttTaskTrig.wBeginDay = stNow.wDay;
//// ttTaskTrig.wStartHour = stNow.wHour;
//// ttTaskTrig.wStartMinute = stNow.wMinute;
////
//// ttTaskTrig.MinutesDuration = MINUTES_IN_A_DAY;
//// ttTaskTrig.MinutesInterval = ulTime / SECONDS_IN_A_MINUTE;
//// ttTaskTrig.TriggerType = TASK_TIME_TRIGGER_DAILY;
////
//// ttTaskTrig.Type.Daily.DaysInterval = 1;
////
//// if(wIdle)
//// {
//// __MPC_EXIT_IF_METHOD_FAILS(hr, pScheduledWorkItem->SetIdleWait( wIdle, 0x7FFF ));
//// __MPC_EXIT_IF_METHOD_FAILS(hr, pScheduledWorkItem->SetFlags ( TASK_FLAG_START_ONLY_IF_IDLE ));
//// }
////
//// // Add this trigger to the task.
//// __MPC_EXIT_IF_METHOD_FAILS(hr, pTaskTrigger->SetTrigger( &ttTaskTrig ));
//// }
////
//// //
//// // Make the changes permanent.
//// //
//// {
//// CComPtr<IPersistFile> pIPF;
////
//// __MPC_EXIT_IF_METHOD_FAILS(hr, pTask->QueryInterface( IID_IPersistFile, (void **)&pIPF ));
////
//// __MPC_EXIT_IF_METHOD_FAILS(hr, pIPF->Save( NULL, FALSE ));
//// }
////
////
//// hr = S_OK;
////
////
//// __HCP_FUNC_CLEANUP;
////
//// __HCP_FUNC_EXIT(hr);
////}
////
////HRESULT CPCHSystemMonitor::TaskScheduler_Remove()
////{
//// __HCP_FUNC_ENTRY( "CPCHSystemMonitor::TaskScheduler_Remove" );
////
//// HRESULT hr;
//// CComPtr<ITaskScheduler> pTaskScheduler;
//// CComBSTR bstrTaskName;
////
////
//// ////////////////////////////////////////
////
//// __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::LocalizeString( IDS_HELPSVC_TASKNAME, bstrTaskName ));
////
//// //
//// // First create the task scheduler.
//// //
//// __MPC_EXIT_IF_METHOD_FAILS(hr, ::CoCreateInstance( CLSID_CTaskScheduler, NULL, CLSCTX_INPROC_SERVER, IID_ITaskScheduler, (void**)&pTaskScheduler ));
////
////
//// if(FAILED(hr = pTaskScheduler->Delete( bstrTaskName )))
//// {
//// if(hr != HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
//// {
//// __MPC_TRACE_HRESULT(hr);
//// __MPC_FUNC_LEAVE;
//// }
//// }
////
////
//// hr = S_OK;
////
////
//// __HCP_FUNC_CLEANUP;
////
//// __HCP_FUNC_EXIT(hr);
////}
////////////////////////////////////////////////////////////////////////////////
HRESULT CPCHSystemMonitor::Startup()
{
__HCP_FUNC_ENTRY( "CPCHSystemMonitor::Startup" );
HRESULT hr;
//
// This forces the Content Store to be loaded.
//
__MPC_EXIT_IF_METHOD_FAILS(hr, CPCHContentStore::s_GLOBAL->Acquire());
__MPC_EXIT_IF_METHOD_FAILS(hr, CPCHContentStore::s_GLOBAL->Release());
////////////////////////////////////////////////////////////////////////////////
//
// Force the loading of the cache.
//
{
Taxonomy::LockingHandle handle;
__MPC_EXIT_IF_METHOD_FAILS(hr, Taxonomy::InstalledInstanceStore::s_GLOBAL->GrabControl( handle ));
}
__MPC_EXIT_IF_METHOD_FAILS(hr, EnsureStarted());
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr);
}