windows-nt/Source/XPSP1/NT/ds/security/services/scerpc/escprov/operation.cpp

1568 lines
47 KiB
C++
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
// operation.cpp, implementation of CSceOperation class
// Copyright (c)1997-1999 Microsoft Corporation
//
//////////////////////////////////////////////////////////////////////
#include "precomp.h"
#include "operation.h"
#include "persistmgr.h"
#include "requestobject.h"
#include <io.h>
#include "extbase.h"
#include "sequence.h"
#include "sceprov.h"
#include "Tranx.h"
/*
Routine Description:
Name:
CSceOperation::CSceOperation
Functionality:
This is the constructor. Pass along the parameters to the base class
Virtual:
No (you know that, constructor won't be virtual!)
Arguments:
pKeyChain - Pointer to the ISceKeyChain COM interface which is prepared
by the caller who constructs this instance.
pNamespace - Pointer to WMI namespace of our provider (COM interface).
Passed along by the caller. Must not be NULL.
pCtx - Pointer to WMI context object (COM interface). Passed along
by the caller. It's up to WMI whether this interface pointer is NULL or not.
Return Value:
None as any constructor
Notes:
if you create any local members, think about initialize them here
*/
CSceOperation::CSceOperation (
IN ISceKeyChain * pKeyChain,
IN IWbemServices * pNamespace,
IN IWbemContext * pCtx
)
:
CGenericClass(pKeyChain, pNamespace, pCtx)
{
}
/*
Routine Description:
Name:
CSceOperation::ExecMethod
Functionality:
Called by CRequestObject to execute a method supported by Sce_Operation class.
This function will also trigger the extension classes method execution. This is
the entry point of all our Configure, Import/Export actitivities.
Virtual:
Yes.
Arguments:
bstrPath - Template's path (file name).
bstrMethod - method's name.
bIsInstance - if this is an instance, should always be false.
pInParams - Input parameter from WMI to the method execution.
pHandler - sink that informs WMI of execution results.
pCtx - the usual context that passes around to make WMI happy.
Return Value:
Success: many different success code (use SUCCEEDED(hr) to test)
Failure: various errors code.
Notes:
*/
HRESULT
CSceOperation::ExecMethod (
IN BSTR bstrPath,
IN BSTR bstrMethod,
IN bool bIsInstance,
IN IWbemClassObject * pInParams,
IN IWbemObjectSink * pHandler,
IN IWbemContext * pCtx
)
{
if ( pInParams == NULL || pHandler == NULL )
{
return WBEM_E_INVALID_PARAMETER;
}
HRESULT hr=WBEM_S_NO_ERROR;
METHODTYPE mtAction;
if ( !bIsInstance )
{
//
//Static Methods
//
if(0 == _wcsicmp(bstrMethod, pwMethodImport))
{
mtAction = METHODTYPE_IMPORT;
}
else if(0 == _wcsicmp(bstrMethod, pwMethodExport))
{
mtAction = METHODTYPE_EXPORT;
}
else if(0 == _wcsicmp(bstrMethod, pwMethodApply))
{
mtAction = METHODTYPE_APPLY;
}
else
{
hr = WBEM_E_NOT_SUPPORTED;
}
}
else
{
//
//Non-Static Methods
//
hr = WBEM_E_NOT_SUPPORTED;
}
if ( FAILED(hr) )
{
return hr;
}
//
// will cache various SCE operation's status return value
//
SCESTATUS rc;
//
// enum for recognizing various operations (methods)
//
DWORD Option;
//
// parse the input parameters
//
CComBSTR bstrDatabase;
CComBSTR bstrTemplate;
CComBSTR bstrLog;
CComBSTR bstrCfg;
UINT uiStatus = 0;
CComBSTR bstrReturnValue(L"ReturnValue");
CComPtr<IWbemClassObject> srpClass;
CComPtr<IWbemClassObject> srpOutClass;
CComPtr<IWbemClassObject> srpReturnValObj;
//
// attach a WMI object to the property mgr.
// This will always succeed.
//
CScePropertyMgr SceInParam;
SceInParam.Attach(pInParams);
CComBSTR bstrClassName;
m_srpKeyChain->GetClassName(&bstrClassName);
//
// to avoid reentrance to this function by different threads (which may cause
// serious system consistency problems).
// ***************************************************************************
// *****don't blindly return. Allow us to leave the Critical section*****
// ***************************************************************************
//
s_OperationCS.Enter();
try
{
//
// g_LogOption is global variable. Need protection.
//
g_CS.Enter();
//
// update the logging operations
//
g_LogOption.GetLogOptionsFromWbemObject(m_srpNamespace);
g_CS.Leave();
//
// need to find out what methods this class really supports. For that purpose
// we need a definition object of this class.
//
m_srpNamespace->GetObject(bstrClassName, 0, pCtx, &srpClass, NULL);
if(SUCCEEDED(hr))
{
//
// does it really supports this method?
//
if(SUCCEEDED(hr = srpClass->GetMethod(bstrMethod, 0, NULL, &srpOutClass)))
{
if(SUCCEEDED(hr = srpOutClass->SpawnInstance(0, &srpReturnValObj)))
{
//
// execute a method is on a database template (even though our extension
// classes are store neutral). This is due to the SCE engine side's implementation.
// Get DatabaseName. No template name, no action can be taken.
//
BOOL bDB=FALSE;
hr = SceInParam.GetExpandedPath(pDatabasePath, &bstrDatabase, &bDB);
if (hr == WBEM_S_RESET_TO_DEFAULT)
{
hr = WBEM_E_INVALID_PARAMETER;
}
if(SUCCEEDED(hr))
{
//
// Again, at this moment, SCE only supports configuring database.
// however, that is not true for extension classes
//
BOOL bSCEConfigure = bDB;
if ( SUCCEEDED(hr) )
{
//
// get area mask, which determines which area the method will be applied.
//
DWORD dwAreas=0;
hr = SceInParam.GetProperty(pAreaMask, &dwAreas);
if ( hr == WBEM_S_RESET_TO_DEFAULT )
{
dwAreas = AREA_ALL;
}
bool bOverwrite=FALSE;
switch ( mtAction )
{
case METHODTYPE_IMPORT:
case METHODTYPE_EXPORT:
//
//Get TemplateName, not exist for the apply method
//
hr = SceInParam.GetExpandedPath(pTemplatePath, &bstrTemplate, &bDB);
if ( hr == WBEM_S_RESET_TO_DEFAULT && bDB)
{
hr = WBEM_E_INVALID_METHOD_PARAMETERS;
}
if ( SUCCEEDED(hr) && mtAction == METHODTYPE_IMPORT )
{
//
// get overwrite flag
//
hr = SceInParam.GetProperty(pOverwrite, &bOverwrite);
}
else
{
//
// make sure the template name has only single back slash
// import method doesn't need to do this because it takes
// names in both single slash and double back slash
//
hr = MakeSingleBackSlashPath(bstrTemplate, L'\\', &bstrCfg);
if (SUCCEEDED(hr))
{
bstrTemplate = bstrCfg;
}
}
break;
case METHODTYPE_APPLY:
//
// get LogName, optional
//
hr = SceInParam.GetExpandedPath(pLogFilePath, &bstrLog, &bDB);
if ( SUCCEEDED(hr) && bDB )
{
//
// can't log into a database
//
hr = WBEM_E_INVALID_METHOD_PARAMETERS;
}
break;
default:
hr = WBEM_E_INVALID_PARAMETER;
break;
}
//
// prepare a logger. It can log various execution results
//
hr = m_clsResLog.Initialize(bstrLog, SCEWMI_OPERATION_CLASS, m_srpNamespace, pCtx);
if ( SUCCEEDED(hr) )
{
//
// process options
//
if ( bOverwrite )
{
Option = SCE_OVERWRITE_DB;
}
else
{
Option = SCE_UPDATE_DB;
}
if ( (LPCWSTR)bstrLog == NULL || wcslen(bstrLog) == 0)
{
Option |= SCE_DISABLE_LOG;
}
else
{
Option |= SCE_VERBOSE_LOG;
}
HRESULT hrExe = WBEM_NO_ERROR;
try
{
switch ( mtAction )
{
case METHODTYPE_IMPORT:
Option |= SCE_NO_CONFIG;
//
// fall through
//
case METHODTYPE_APPLY:
//
//Call for import/configure
//
if (METHODTYPE_APPLY == mtAction)
{
CTranxID::BeginTransaction(bstrDatabase);
}
//
// see comments where this variable is declared
//
if (bSCEConfigure)
{
rc = SceConfigureSystem(
NULL,
((LPCWSTR)bstrTemplate == NULL) ? NULL : bstrTemplate,
bstrDatabase,
((LPCWSTR)bstrLog == NULL) ? NULL : bstrLog,
Option,
(AREA_INFORMATION)dwAreas,
NULL,
NULL,
NULL
);
//
// SCE returned errors needs to be translated to HRESULT.
//
hr = ProvDosErrorToWbemError(ProvSceStatusToDosError(rc));
//
// Log the execution result.
// will ignore the return result, see declaration of m_clsResLog for reasoning
//
if (mtAction == METHODTYPE_IMPORT)
{
m_clsResLog.LogResult(hr, NULL, pInParams, NULL, pwMethodImport, NULL, IDS_IMPORT_TEMPLATE, bstrDatabase);
}
else
{
m_clsResLog.LogResult(hr, NULL, pInParams, NULL, pwMethodApply, NULL, IDS_CONFIGURE_DB, bstrDatabase);
}
}
if ( mtAction == METHODTYPE_APPLY )
{
//
// for Sce_Pod
//
hrExe = ProcessAttachmentData(pCtx,
bstrDatabase,
((LPCWSTR)bstrLog == NULL) ? NULL : bstrLog,
pwMethodApply,
Option,
(DWORD *)&rc);
//
// track the first error
//
if (SUCCEEDED(hr))
{
hr = hrExe;
}
//
// we will continue our execution even if hr has indicated failures
//
//
// for Sce_EmbedFO, error will be loged inside embed class's method execution
//
hrExe = ExecMethodOnForeignObjects(pCtx,
bstrDatabase,
((LPCWSTR)bstrLog == NULL) ? NULL : bstrLog,
pwMethodApply,
Option,
(DWORD *)&rc);
//
// track the first error
//
if (SUCCEEDED(hr))
{
hr = hrExe;
}
// for Sce_LinkFO
//hr = ExecMethodOnForeignObjects(pCtx,
// bstrDatabase,
// ((LPCWSTR)bstrLog == NULL) ? NULL : bstrLog,
// SCEWMI_LINK_BASE_CLASS,
// pwMethodApply,
// Option,
// (DWORD *)&rc);
if ( SUCCEEDED(hr) && rc != ERROR_SUCCESS )
{
uiStatus = rc;
}
}
if (METHODTYPE_APPLY == mtAction)
{
CTranxID::EndTransaction();
}
break;
case METHODTYPE_EXPORT:
uiStatus = SceSetupGenerateTemplate(
NULL,
bstrDatabase,
FALSE,
((LPCWSTR)bstrTemplate == NULL) ? NULL : bstrTemplate,
((LPCWSTR)bstrLog == NULL) ? NULL : bstrLog,
(AREA_INFORMATION)dwAreas
);
//
// SCE returned errors needs to be translated to HRESULT.
//
hr = ProvDosErrorToWbemError(ProvSceStatusToDosError(uiStatus));
//
// will ignore the return result, see declaration of m_clsResLog for reasoning
//
m_clsResLog.LogResult(hr, NULL, pInParams, NULL, pwMethodExport, NULL, IDS_EXPORT_DB, bstrDatabase);
break;
default:
//
//hr = WBEM_E_NOT_SUPPORTED;
//
break;
}
}
catch(...)
{
uiStatus = RPC_E_SERVERFAULT;
}
if ( SUCCEEDED(hr) )
{
//
//Set up ReturnValue
//
VARIANT v;
::VariantInit(&v);
V_VT(&v) = VT_I4;
V_I4(&v) = uiStatus;
if(SUCCEEDED(hr = srpReturnValObj->Put(bstrReturnValue, 0, &v, NULL)))
{
pHandler->Indicate(1, &srpReturnValObj);
}
::VariantClear(&v);
}
}
}
}
}
}
}
}
catch (...)
{
}
s_OperationCS.Leave();
return hr;
}
/*
Routine Description:
Name:
CSceOperation::ProcessAttachmentData
Functionality:
Private helper. Called by CSceOperation::ExecMethod to execute a method supported by all
Sce_Pod classes.
Virtual:
no.
Arguments:
pCtx - the usual context that passes around to make WMI happy.
pszDatabase - Template's path (file name).
pszLog - the log file's path.
bstrMethod - method's name.
Option - doesn't seem to be used any more.
pdwStatus - the returned SCESTATUS value.
Return Value:
Success: many different success code (use SUCCEEDED(hr) to test)
Failure: various errors codes. If for multiple instances, one of them return errors during
execution of the methods, we will try to return to first such error.
Notes:
*/
HRESULT
CSceOperation::ProcessAttachmentData (
IN IWbemContext * pCtx,
IN LPCWSTR pszDatabase,
IN LPCWSTR pszLog OPTIONAL,
IN LPCWSTR pszMethod,
IN DWORD Option,
OUT DWORD * pdwStatus
)
{
if ( pszDatabase == NULL || pdwStatus == NULL )
{
return WBEM_E_INVALID_PARAMETER;
}
*pdwStatus = 0;
HRESULT hr;
//
// get all inherited classes from pszExtBaseClass (currently, we have Sce_Pod, Sce_EmbedFO, Sce_LinkFO
// one class per attachment
//
CComBSTR bstrSuperClass(SCEWMI_POD_CLASS);
if ( (BSTR)bstrSuperClass == NULL )
{
return WBEM_E_OUT_OF_MEMORY;
}
CComPtr<IEnumWbemClassObject> srpEnum;
ULONG n=0;
hr = m_srpNamespace->CreateClassEnum(bstrSuperClass,
WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_FORWARD_ONLY,
pCtx,
&srpEnum
);
if (FAILED(hr))
{
//
// will ignore the return result, see declaration of m_clsResLog for reasoning
//
m_clsResLog.LogResult(hr, NULL, NULL, NULL, L"CSceOperation::ProcessAttachmentData", NULL, IDS_CREATE_CLASSENUM, bstrSuperClass);
return hr;
}
HRESULT hrFirstError = WBEM_NO_ERROR;
if (SUCCEEDED(hr))
{
CComBSTR bstrMethod(pszMethod);
//
// build the input parameters
//
//
// each instance returned should represent one attachment
//
do {
CComPtr<IWbemClassObject> srpObj;
CComPtr<IWbemClassObject> srpInClass;
hr = srpEnum->Next(WBEM_INFINITE, 1, &srpObj, &n);
//
// failed to enumerate or doesn't return anything, we are fine with that
// since if the store doesn't contain any instances, we don't have to do anything
// and it is not an error
//
if (FAILED(hr) || hr == WBEM_S_FALSE )
{
hr = WBEM_NO_ERROR;
break;
}
if (SUCCEEDED(hr) && n>0 )
{
//
// find one attachment class
//
CComVariant varClass;
//
// need this class's name
//
if(SUCCEEDED(hr=srpObj->Get(L"__CLASS", 0, &varClass, NULL, NULL)))
{
if (SUCCEEDED(hr))
{
if (varClass.vt != VT_BSTR)
{
break;
}
}
if ( SUCCEEDED(hr) )
{
//
// create input parameters
//
hr = srpObj->GetMethod(bstrMethod, 0, &srpInClass, NULL);
}
// everything is fine, we will then execute this pod's method
if ( SUCCEEDED(hr) )
{
hr = ExecutePodMethod(pCtx, pszDatabase, pszLog, varClass.bstrVal, bstrMethod, srpInClass, pdwStatus);
}
}
if (FAILED(hr) && SUCCEEDED(hrFirstError))
{
hrFirstError = hr;
}
}
} while (true);
}
//
// will report the first error
//
return SUCCEEDED(hrFirstError) ? hr : hrFirstError;
}
/*
Routine Description:
Name:
CSceOperation::ExecMethodOnForeignObjects
Functionality:
Private helper. Called by CSceOperation::ExecMethod to execute a method supported by all
extension classes.
Virtual:
no.
Arguments:
pCtx - the usual context that passes around to make WMI happy.
pszDatabase - Template's path (file name).
pszLog - the log file's path.
bstrMethod - method's name.
Option - Log options.
pdwStatus - the returned SCESTATUS value.
Return Value:
Success: many different success code (use SUCCEEDED(hr) to test)
Failure: various errors codes. If for multiple instances, one of them return errors during
execution of the methods, we will try to return to first such error.
Notes:
(1) For each method, we may have a particular order for the classes to execute the method.
Our CSequencer class knows how to create the order.
(2) We will report any error, but at this point, we will continue to execute other instances'
method even if the previous instance has an error.
(3) We will always capture the first error and return it to the caller.
(4) We should also log errors.
*/
HRESULT
CSceOperation::ExecMethodOnForeignObjects (
IN IWbemContext * pCtx,
IN LPCWSTR pszDatabase,
IN LPCWSTR pszLog OPTIONAL,
IN LPCWSTR pszMethod,
IN DWORD Option,
OUT DWORD * pdwStatus
)
{
if ( pszDatabase == NULL || pdwStatus == NULL )
{
return WBEM_E_INVALID_PARAMETER;
}
*pdwStatus = 0;
//
// build the class sequence for the method
// we need to build the sequence of classes for this method
//
CSequencer seq;
HRESULT hr = seq.Create(m_srpNamespace, pszDatabase, pszMethod);
if (FAILED(hr))
{
//
// will ignore the return result, see declaration of m_clsResLog for reasoning
//
m_clsResLog.LogResult(hr, NULL, NULL, NULL, L"CSceOperation::ExecMethodOnForeignObjects", NULL, IDS_CREATE_SEQUENCER, pszDatabase);
return hr;
}
//
// this variable will cache all classes that have been called to execute
//
MapExecutedClasses mapExcuted;
//
// we will execute the method according this sequence first
//
HRESULT hrFirstError = WBEM_NO_ERROR;;
const COrderNameList* pClsList = NULL;
if (SUCCEEDED(seq.GetOrderList(&pClsList)) && pClsList)
{
DWORD dwEnumHandle = 0;
//
// pList must not be released here
//
const CNameList* pList = NULL;
while (SUCCEEDED(pClsList->GetNext(&pList, &dwEnumHandle)) && pList)
{
//
// we will report any error
//
for (int i = 0; i < pList->m_vList.size(); i++)
{
hr = ExeClassMethod(pCtx, pszDatabase, pszLog, pList->m_vList[i], pszMethod, Option, pdwStatus, &mapExcuted);
//
// catch the first error to return
//
if (FAILED(hr) && SUCCEEDED(hrFirstError))
{
hrFirstError = hr;
}
}
//
// reset its value for next loop
//
pList = NULL;
}
}
//
// now, we need to execute the rest of the embedded classes whose name doesn't
// show up in the sequencer
//
//
// try all inherited classes from SCEWMI_EMBED_BASE_CLASS
//
hr = ExeClassMethod(pCtx, pszDatabase, pszLog, SCEWMI_EMBED_BASE_CLASS, pszMethod, Option, pdwStatus, &mapExcuted);
//
// catch the first error to return
//
if (FAILED(hr) && SUCCEEDED(hrFirstError))
{
hrFirstError = hr;
}
//
// now clean up the map that caches our already-executed classes map
//
MapExecutedClasses::iterator it = mapExcuted.begin();
while (it != mapExcuted.end())
{
::SysFreeString((*it).first);
++it;
}
return FAILED(hrFirstError) ? hrFirstError : hr;
}
/*
Routine Description:
Name:
CSceOperation::ExeClassMethod
Functionality:
Private helper. Called to execute the method on a particular embedding class.
Virtual:
no.
Arguments:
pCtx - the usual context that passes around to make WMI happy.
pszDatabase - Template's path (file name).
pszClsName - individual class name.
pszLog - the log file's path.
bstrMethod - method's name.
Option - Log options, not really used at this time. This is for SCE engine.
pdwStatus - the returned SCESTATUS value.
pExecuted - used to update the list of classes that are execute during this call.
Return Value:
Success: many different success code (use SUCCEEDED(hr) to test)
Failure: various errors codes. If for multiple instances, one of them return errors during
execution of the methods, we will try to return to first such error..
Notes:
*/
HRESULT
CSceOperation::ExeClassMethod (
IN IWbemContext * pCtx,
IN LPCWSTR pszDatabase,
IN LPCWSTR pszLog OPTIONAL,
IN LPCWSTR pszClsName,
IN LPCWSTR pszMethod,
IN DWORD Option,
OUT DWORD * pdwStatus,
IN OUT MapExecutedClasses * pExecuted
)
{
//
// WMI needs bstr names
//
CComBSTR bstrClass(pszClsName);
if ( (BSTR)bstrClass == NULL )
{
return WBEM_E_OUT_OF_MEMORY;
}
//
// ask WMI for all those classes of the given name pszClsName
// We need to enumerate because there might be sub-classes of this given name.
//
CComPtr<IEnumWbemClassObject> srpEnum;
ULONG lRetrieved = 0;
HRESULT hr = m_srpNamespace->CreateClassEnum(bstrClass,
WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_FORWARD_ONLY,
pCtx,
&srpEnum
);
if (FAILED(hr))
{
//
// will ignore the return result, see declaration of m_clsResLog for reasoning
//
m_clsResLog.LogResult(hr, NULL, NULL, NULL, L"CSceOperation::ExeClassMethod", NULL, IDS_CREATE_CLASSENUM, pszClsName);
return hr;
}
//
// determines if this class has any sub-classes or not
//
ULONG lTotlRetrieved = 0;
//
// catch the first error to return
//
HRESULT hrFirstError = WBEM_NO_ERROR;
if (SUCCEEDED(hr))
{
CComBSTR bstrMethod(pszMethod);
do {
CComPtr<IWbemClassObject> srpObj;
CComPtr<IWbemClassObject> srpInClass;
//
// get one class a time
//
hr = srpEnum->Next(WBEM_INFINITE, 1, &srpObj, &lRetrieved);
lTotlRetrieved += lRetrieved;
//
// if the class has no subclass, then we need to try the class itself. We will allow this to fail,
// meaning that we can't find any instance of this class
//
if ((FAILED(hr) || hr == WBEM_S_FALSE) )
{
//
// if we have successfully gone through some sub-classes, then we can break
// because it tells us that it doesn't have any more subs.
//
if (lTotlRetrieved > 0)
{
break;
}
//
// try to get the definition of this class in case this is not an abstract one
//
else if (FAILED(m_srpNamespace->GetObject(bstrClass, 0, pCtx, &srpObj, NULL)))
{
m_clsResLog.LogResult(hr, NULL, NULL, NULL, L"CSceOperation::ExeClassMethod", NULL, IDS_GET_CLASS_INSTANCE, pszClsName);
break;
}
}
//
// we truly have an object of this class
//
if (SUCCEEDED(hr) && srpObj)
{
//
// get the class's name. Remember, we might be retrieving based on the base class's name
// therefore, bstrClass may not be really the instance's class name
//
CComVariant varClass;
if(SUCCEEDED(hr = srpObj->Get(L"__CLASS", 0, &varClass, NULL, NULL)))
{
if (SUCCEEDED(hr))
{
if (varClass.vt != VT_BSTR)
{
break;
}
}
//
// see if the class has been executed before
//
MapExecutedClasses::iterator it = pExecuted->find(varClass.bstrVal);
//
// if not yet executed, then of course, we need to execute it
//
if (it == pExecuted->end())
{
if ( SUCCEEDED(hr) )
{
hr = srpObj->GetMethod(bstrMethod, 0, &srpInClass, NULL);
}
if ( SUCCEEDED(hr) )
{
hr = ExecuteExtensionClassMethod(pCtx, pszDatabase, pszLog, varClass.bstrVal, bstrMethod, srpInClass, pdwStatus);
}
//
// add it to the already-executed class map, the map takes the ownership of the bstr in the variant
// and that is why we can't let the variant to go ahead destroying itself.
//
pExecuted->insert(MapExecutedClasses::value_type(varClass.bstrVal, 0));
//
// prevent the variant from self-destruction
//
varClass.bstrVal = NULL;
varClass.vt = VT_EMPTY;
}
}
else
{
m_clsResLog.LogResult(hr, NULL, NULL, NULL, L"CSceOperation::ExeClassMethod", NULL, IDS_GET_CLASS_DEFINITION, pszClsName);
}
}
//
// don't overwrite the first error
//
if (FAILED(hr) && SUCCEEDED(hrFirstError))
{
hrFirstError = hr;
}
//
// don't loop if this is not a subclass enumeration
//
if (lRetrieved == 0)
{
break;
}
} while (true);
}
//
// will report first error
//
return SUCCEEDED(hrFirstError) ? hr : hrFirstError;
}
/*
Routine Description:
Name:
CSceOperation::ExecutePodMethod
Functionality:
Private helper. Called to execute each Pod's method.
Virtual:
no.
Arguments:
pCtx - the usual context that passes around to make WMI happy.
pszDatabase - Template's path (file name).
pszLog - the log file's path.
bstrMethod - method's name.
Option - doesn't seem to be used any more.
pInClass - input parameter's spawning object.
pdwStatus - the returned SCESTATUS value.
Return Value:
Success: many different success code (use SUCCEEDED(hr) to test)
Failure: various errors codes. If for multiple instances, one of them return errors during
execution of the methods, we will try to try to first such error.
Notes:
*/
HRESULT CSceOperation::ExecutePodMethod (
IN IWbemContext * pCtx,
IN LPCWSTR pszDatabase,
IN LPCWSTR pszLog OPTIONAL,
IN BSTR bstrClass,
IN BSTR bstrMethod,
IN IWbemClassObject * pInClass,
OUT DWORD * pdwStatus
)
{
//
// get ready to fill in the input parameters. Without that, we can't make
// a successful method call.
//
CComPtr<IWbemClassObject> srpInParams;
HRESULT hr = pInClass->SpawnInstance(0, &srpInParams);
if (FAILED(hr))
{
m_clsResLog.LogResult(hr, NULL, NULL, NULL, L"CSceOperation::ExecutePodMethod", NULL, IDS_SPAWN_INSTANCE, bstrClass);
}
if (SUCCEEDED(hr))
{
//
// try to fill in in-bound parameter's properties
//
//
// CScePropertyMgr helps us to access WMI object's properties
// create an instance and attach the WMI object to it.
// This will always succeed.
//
CScePropertyMgr ScePropMgr;
ScePropMgr.Attach(srpInParams);
//
// fill in the in parameter
//
hr = ScePropMgr.PutProperty(pStorePath, pszDatabase);
if (FAILED(hr))
{
//
// indicating that the class's pStorePath key property can't be put
//
CComBSTR bstrExtraInfo = bstrClass;
bstrExtraInfo += CComBSTR(L".");
bstrExtraInfo += CComBSTR(pStorePath);
m_clsResLog.LogResult(hr, NULL, NULL, NULL, L"CSceOperation::ExecutePodMethod", NULL, IDS_PUT_PROPERTY, bstrExtraInfo);
return hr;
}
//
// fill in the in parameter
//
hr = ScePropMgr.PutProperty(pLogFilePath, pszLog);
if ( FAILED(hr) )
{
//
// indicating that the class's pLogFilePath key property can't be put
//
CComBSTR bstrExtraInfo = bstrClass;
bstrExtraInfo += CComBSTR(L".");
bstrExtraInfo += CComBSTR(pLogFilePath);
m_clsResLog.LogResult(hr, NULL, NULL, NULL, L"CSceOperation::ExecutePodMethod", NULL, IDS_PUT_PROPERTY, bstrExtraInfo);
}
else
{
//
// create the out-bound parameter
//
CComPtr<IWbemClassObject> srpOutParams;
//
// make a call the the attachment provider
// must be in synchronous mode
//
hr = m_srpNamespace->ExecMethod(bstrClass,
bstrMethod,
0,
pCtx,
srpInParams,
&srpOutParams,
NULL
);
if ( SUCCEEDED(hr) && srpOutParams )
{
//
// retrieve the return value
//
//
// CScePropertyMgr helps us to access WMI object's properties
// create an instance and attach the WMI object to it.
// This will always succeed.
//
CScePropertyMgr SceOutReader;
SceOutReader.Attach(srpOutParams);
hr = SceOutReader.GetProperty(L"ReturnValue", pdwStatus);
}
//
// ignore not found error
// if there is no data for an attachment
//
if ( hr == WBEM_E_NOT_FOUND || hr == WBEM_E_INVALID_QUERY)
{
hr = WBEM_S_NO_ERROR;
}
}
}
return hr;
}
/*
Routine Description:
Name:
CSceOperation::ExecuteExtensionClassMethod
Functionality:
Private helper. Called to execute the method on a particular embedding class instance.
Virtual:
no.
Arguments:
pCtx - the usual context that passes around to make WMI happy.
pszDatabase - Template's path (file name).
pszClsName - individual class name.
pszLog - the log file's path.
bstrMethod - method's name.
Option - Log options, not really used at this time. This is for SCE engine.
pInClass - input parameter's spawning object.
pdwStatus - the returned SCESTATUS value.
Return Value:
Success: many different success code (use SUCCEEDED(hr) to test)
Failure: various errors codes. If for multiple instances, one of them return errors during
execution of the methods, we will try to return to first such error..
Notes:
This is the per-instance method call, the final leg of method execution process.
*/
HRESULT
CSceOperation::ExecuteExtensionClassMethod (
IN IWbemContext * pCtx,
IN LPCWSTR pszDatabase,
IN LPCWSTR pszLog OPTIONAL,
IN BSTR bstrClass,
IN BSTR bstrMethod,
IN IWbemClassObject * pInClass,
OUT DWORD * pdwStatus
)
{
//
// create the input parameter instance.
//
CComPtr<IWbemClassObject> srpInParams;
HRESULT hr = pInClass->SpawnInstance(0, &srpInParams);
//
// catch the first error to return
//
HRESULT hrFirstError = WBEM_NO_ERROR;
if (SUCCEEDED(hr))
{
//
// create a blank object
//
CComPtr<IWbemClassObject> srpSpawn;
hr = m_srpNamespace->GetObject(bstrClass, 0, m_srpCtx, &srpSpawn, NULL);
if (FAILED(hr))
{
return hr;
}
//
// CScePropertyMgr helps us to access WMI object's properties
// create an instance and attach the WMI object to it.
// This will always succeed.
//
CScePropertyMgr ScePropMgr;
ScePropMgr.Attach(srpInParams);
hr = ScePropMgr.PutProperty(pLogFilePath, pszLog);
if (FAILED(hr))
{
//
// indicating that the class's pLogFilePath key property can't be put
//
CComBSTR bstrExtraInfo = bstrClass;
bstrExtraInfo += CComBSTR(L".");
bstrExtraInfo += CComBSTR(pLogFilePath);
m_clsResLog.LogResult(hr, NULL, NULL, NULL, L"CSceOperation::ExecuteExtensionClassMethod", NULL, IDS_PUT_PROPERTY, bstrExtraInfo);
}
//
// Prepare a store (for persistence) for this store path (file)
//
CSceStore SceStore;
SceStore.SetPersistPath(pszDatabase);
//
// now create the list for the class so that we can get the path of the instances.
// this way, we don't need to query WMI for instances. That is very slow and a lot of redundant
// reading.
//
CExtClassInstCookieList clsInstCookies;
//
// we need the foreign class's info for the instance list
//
const CForeignClassInfo* pFCInfo = g_ExtClasses.GetForeignClassInfo(m_srpNamespace, pCtx, bstrClass);
if (pFCInfo == NULL)
{
hr = WBEM_E_NOT_FOUND;
}
else
{
hr = clsInstCookies.Create(&SceStore, bstrClass, pFCInfo->m_pVecKeyPropNames);
}
if (FAILED(hr))
{
m_clsResLog.LogResult(hr, NULL, NULL, NULL, L"CSceOperation::ExecuteExtensionClassMethod", NULL, IDS_CREATE_INSTANCE_LIST, bstrClass);
return hr;
}
//
// we have the instance list, so, ready to get the path and execute the method
//
if (SUCCEEDED(hr))
{
DWORD dwResumeHandle = 0;
//
// get the string version of the compound key, which can be
// used to get the object's path
//
CComBSTR bstrEachCompKey;
hr = clsInstCookies.Next(&bstrEachCompKey, NULL, &dwResumeHandle);
while (SUCCEEDED(hr) && hr != WBEM_S_NO_MORE_DATA)
{
//
// as long as there is more item, keep looping
//
if (SUCCEEDED(hr) && hr != WBEM_S_NO_MORE_DATA)
{
//
// WMI only takes the path (instead of the object) to execute the method.
// Now, we have the instanace list and it has given its the string version
// of the compound key, we can ask CScePersistMgr for the object path
//
CComBSTR bstrObjPath;
hr = ::GetObjectPath(srpSpawn, SceStore.GetExpandedPath(), bstrEachCompKey, &bstrObjPath);
//
// we get the instanace's path
//
if (SUCCEEDED(hr))
{
//
// any execution error will be logged in the calling function
//
CComPtr<IWbemClassObject> srpOutParams;
hr = m_srpNamespace->ExecMethod(bstrObjPath,
bstrMethod,
0,
pCtx,
srpInParams,
&srpOutParams,
NULL
);
//
// don't overwrite the first error
//
if (FAILED(hr) && SUCCEEDED(hrFirstError))
{
hrFirstError = hr;
}
}
else
{
m_clsResLog.LogResult(hr, NULL, NULL, NULL, L"CSceOperation::ExecuteExtensionClassMethod", NULL, IDS_GET_FULLPATH, bstrClass);
}
}
//
// get ready to be reused!
//
bstrEachCompKey.Empty();
hr = clsInstCookies.Next(&bstrEachCompKey, NULL, &dwResumeHandle);
}
}
}
return SUCCEEDED(hrFirstError) ? hr : hrFirstError;
}