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.
 
 
 
 
 
 

1506 lines
34 KiB

// MemberAccess.cpp : Implementation of CSsrMemberAccess
#include "stdafx.h"
#include "SSRTE.h"
#include "SSRLog.h"
#include "MemberAccess.h"
#include "global.h"
#include "util.h"
static bool SsrPIsValidActionType ( DWORD dwType )
{
return ( (dwType & SSR_ACTION_PREPARE) ||
(dwType & SSR_ACTION_APPLY)
);
}
//
// returning bool instead of bool is on purpose!
//
static bool SsrPIsDefaultAction ( DWORD dwType )
{
return ( (dwType & SSR_ACTION_PREPARE) ||
(dwType & SSR_ACTION_APPLY)
);
}
static bool SsrPIsSupportedRegValueType (DWORD dwType)
{
return (dwType == REG_SZ || dwType == REG_MULTI_SZ || dwType == REG_DWORD);
}
//---------------------------------------------------------------------
// CSsrMemberAccess implementation
//---------------------------------------------------------------------
/*
Routine Description:
Name:
CSsrMemberAccess::Cleanup
Functionality:
Cleanup the resource held by the object
Virtual:
No.
Arguments:
none.
Return Value:
none.
Notes:
*/
void CSsrMemberAccess::Cleanup()
{
MapMemberAD::iterator it = m_mapMemAD.begin();
MapMemberAD::iterator itEnd = m_mapMemAD.end();
while(it != itEnd)
{
CMemberAD * pVal = (*it).second;
delete pVal;
it++;
}
m_mapMemAD.clear();
m_bstrName.Empty();
m_bstrProgID.Empty();
}
/*
Routine Description:
Name:
CSsrMemberAccess::GetSupportedActions
Functionality:
Get the names of the actions supported by this member
Virtual:
yes.
Arguments:
bDefault - If true, then this function queries the default actions
pvarActionNames - The out parameter that receives the names of the actions of
the given type supported by this member
Return Value:
Success: S_OK if there are actions of the type and the names are returned
S_FALSE if there is no such actions supported by the member.
Failure: various error codes.
Notes:
*/
STDMETHODIMP
CSsrMemberAccess::GetSupportedActions (
IN BOOL bDefault,
OUT VARIANT * pvarActionNames //[out, retval]
)
{
if (pvarActionNames == NULL)
{
return E_INVALIDARG;
}
//
// now, create the array of action names
//
::VariantInit(pvarActionNames);
//
// let's see how many actions of this type exists
//
MapMemberAD::iterator it = m_mapMemAD.begin();
MapMemberAD::iterator itEnd = m_mapMemAD.end();
int iCount = 0;
//
// we need to find out how many actions are of the given type
//
while(it != itEnd)
{
CMemberAD * pAD = (*it).second;
_ASSERT(pAD != NULL);
//
// Be aware! Don't simply use bDefault == ::SsrPIsDefaultAction to test
// because bDefault will be -1 when it comes from scripts!
//
if (bDefault && ::SsrPIsDefaultAction(pAD->GetType()) ||
!bDefault && !::SsrPIsDefaultAction(pAD->GetType()))
{
++iCount;
}
++it;
}
if (iCount == 0)
{
return S_FALSE;
}
//
// given the count we just get, now we know how big a safearray
// we need to create.
//
SAFEARRAYBOUND rgsabound[1];
rgsabound[0].lLbound = 0;
rgsabound[0].cElements = iCount;
SAFEARRAY * psa = ::SafeArrayCreate(VT_VARIANT , 1, rgsabound);
HRESULT hr = S_OK;
if (psa == NULL)
{
hr = E_OUTOFMEMORY;
}
else
{
//
// we only add one name at a time
//
long indecies[1] = {0};
it = m_mapMemAD.begin();
while(it != itEnd)
{
CMemberAD * pAD = (*it).second;
_ASSERT(pAD != NULL);
//
// count only those actions that match the requested action type
//
if (bDefault && ::SsrPIsDefaultAction(pAD->GetType()) ||
!bDefault && !::SsrPIsDefaultAction(pAD->GetType()))
{
VARIANT v;
v.vt = VT_BSTR;
v.bstrVal = ::SysAllocString(pAD->GetActionName());
if (v.bstrVal != NULL)
{
hr = ::SafeArrayPutElement(psa, indecies, &v);
::VariantClear(&v);
}
else
{
hr = E_OUTOFMEMORY;
}
if (FAILED(hr))
{
break;
}
indecies[0]++;
}
++it;
}
//
// only return the safearray if everything goes well
//
if (SUCCEEDED(hr))
{
pvarActionNames->vt = VT_ARRAY | VT_VARIANT;
pvarActionNames->parray = psa;
}
else
{
::SafeArrayDestroy(psa);
}
}
return hr;
}
/*
Routine Description:
Name:
CSsrMemberAccess::get_Name
Functionality:
Get the names of the member.
Virtual:
yes.
Arguments:
pbstrName - the BSTR which is the action of the member.
Return Value:
Success: S_OK as long as pbstrName is not NULL (which is invalid)
Failure: various error codes.
Notes:
*/
STDMETHODIMP
CSsrMemberAccess::get_Name (
OUT BSTR * pbstrName // [out, retval]
)
{
if (pbstrName == NULL)
{
return E_INVALIDARG;
}
*pbstrName = ::SysAllocString(m_bstrName);
return (NULL == *pbstrName) ? E_OUTOFMEMORY : S_OK;
}
/*
Routine Description:
Name:
CSsrMemberAccess::get_SsrMember
Functionality:
Return the SsrMember property - the custom ISsrMember object implemented by
the member who desires to implement some custom behavior for certain actions.
Virtual:
yes.
Arguments:
pvarSsrMember - Out parameter receiving the custom ISsrMember object
implemented by the member who desires to implement some
custom behavior for certain actions.
Return Value:
Success: S_OK if this member does have a custom implementation
of ISsrMember.
S_FALSE if this member doesn't have a custom
implementation of ISsrMember.
Failure: various error codes
Notes:
*/
STDMETHODIMP
CSsrMemberAccess::get_SsrMember (
OUT VARIANT * pvarSsrMember //[out, retval]
)
{
if (pvarSsrMember == NULL)
{
return E_INVALIDARG;
}
::VariantInit(pvarSsrMember);
HRESULT hr = S_FALSE;
if (m_bstrProgID != NULL)
{
//
// now create the COM object
//
GUID clsID;
hr = ::CLSIDFromProgID(m_bstrProgID, &clsID);
if (S_OK == hr)
{
ISsrMember * pISsrMember = NULL;
hr = ::CoCreateInstance(clsID,
NULL,
CLSCTX_INPROC_SERVER,
IID_ISsrMember,
(LPVOID*)&pISsrMember
);
if (S_OK == hr)
{
pvarSsrMember->vt = VT_DISPATCH;
pvarSsrMember->pdispVal = pISsrMember;
}
}
}
return hr;
}
/*
Routine Description:
Name:
CSsrMemberAccess::Load
Functionality:
Will create this object based on the information available
from the registry key.
Virtual:
no.
Arguments:
wszMemberFilePath - The path for the member registration XML file.
Return Value:
Success: S_OK if there are concrete member information being
loaded (has action data).
S_FALSE if there is really nothing this member has registered.
Such a member should be discarded because it doesn't contain
anything that SSR can use.
Failure: various error codes.
Notes:
*/
HRESULT
CSsrMemberAccess::Load (
IN LPCWSTR wszMemberFilePath
)
{
if (wszMemberFilePath == NULL || *wszMemberFilePath == L'\0')
{
return E_INVALIDARG;
}
//
// just in case, this object is called to Load twice, clean up everything first
//
Cleanup();
//
// load the DOM
//
CComPtr<IXMLDOMDocument2> srpXmlDom;
HRESULT hr = ::CoCreateInstance(CLSID_DOMDocument40,
NULL,
CLSCTX_SERVER,
IID_IXMLDOMDocument2,
(LPVOID*)(&srpXmlDom)
);
if (FAILED(hr))
{
return hr;
}
hr = SsrPLoadDOM(CComBSTR(wszMemberFilePath), SSR_LOADDOM_VALIDATE_ON_PARSE, srpXmlDom);
if (FAILED(hr))
{
return hr;
}
CComPtr<IXMLDOMElement> srpXMLDocRoot;
hr = srpXmlDom->get_documentElement(&srpXMLDocRoot);
if (FAILED(hr))
{
return hr;
}
//
// Get the UniqueName attribute
//
CComPtr<IXMLDOMNamedNodeMap> srpAttr;
if (SUCCEEDED(hr))
{
CComVariant varAttr;
hr = srpXMLDocRoot->getAttribute(g_bstrAttrUniqueName, &varAttr);
if (FAILED(hr) || varAttr.vt != VT_BSTR)
{
//
// we must have the unique name. This fails, we log and quit
//
return hr;
}
else
{
m_bstrName = varAttr.bstrVal;
varAttr.vt = VT_EMPTY;
}
//
// first, let's see if there is a ProgID value. We will ignore
// any failure of reading the ProgID since it may not be there at all.
//
if (SUCCEEDED(srpXMLDocRoot->getAttribute(g_bstrAttrProgID, &varAttr)) &&
varAttr.vt == VT_BSTR)
{
m_bstrProgID = varAttr.bstrVal;
varAttr.vt = VT_EMPTY;
}
varAttr.Clear();
//
// Let's grab the major and minor versions. Currently, we don't have any
// implementation to enforce them other than that the major version must
// the same as our dll's. Otherwise we quit
//
if (SUCCEEDED(srpXMLDocRoot->getAttribute(g_bstrAttrMajorVersion, &varAttr)))
{
CComVariant varMajor;
if (SUCCEEDED(VariantChangeType(&varMajor, &varAttr, VARIANT_NOVALUEPROP, VT_UI4)))
{
m_ulMajorVersion = varMajor.ulVal;
}
}
if (m_ulMajorVersion != g_ulSsrEngineMajorVersion)
{
return E_SSR_MAJOR_VERSION_MISMATCH;
}
varAttr.Clear();
if (SUCCEEDED(srpXMLDocRoot->getAttribute(g_bstrAttrMinorVersion, &varAttr)))
{
CComVariant varMinor;
if (SUCCEEDED(VariantChangeType(&varMinor, &varAttr, VARIANT_NOVALUEPROP, VT_UI4)))
{
m_ulMinorVersion = varMinor.ulVal;
}
}
}
//
// now, let's load each action
//
CComPtr<IXMLDOMNode> srpActionNode;
hr = srpXMLDocRoot->get_firstChild(&srpActionNode);
bool bLoaded = false;
while (SUCCEEDED(hr) && srpActionNode != NULL)
{
CComBSTR bstrName;
srpActionNode->get_nodeName(&bstrName);
if (_wcsicmp(bstrName, g_bstrSupportedAction) == 0)
{
//
// we only care about SupportedAction elements
//
CMemberAD * pMAD = NULL;
hr = CMemberAD::LoadAD(m_bstrName, srpActionNode, m_bstrProgID, &pMAD);
if (SUCCEEDED(hr))
{
//
// we might load some empty procedure
//
if (pMAD != NULL)
{
const CActionType * pAT = pMAD->GetActionType();
m_mapMemAD.insert(MapMemberAD::value_type(*pAT, pMAD));
bLoaded = true;
}
}
else
{
g_fblog.LogFeedback(SSR_FB_ERROR_LOAD_MEMBER | FBLog_Log,
hr,
wszMemberFilePath,
IDS_XML_LOADING_MEMBER
);
break;
}
}
CComPtr<IXMLDOMNode> srpNext;
hr = srpActionNode->get_nextSibling(&srpNext);
srpActionNode.Release();
srpActionNode = srpNext;
}
if (FAILED(hr))
{
g_fblog.LogError(hr, L"CSsrMemberAccess::Load", wszMemberFilePath);
}
else if (bLoaded)
{
hr = S_OK;
}
return hr;
}
/*
Routine Description:
Name:
CSsrMemberAccess::GetActionDataObject
Functionality:
Will find and return (if found) the CMemberAD that of the given name.
This is a helper function
Virtual:
no.
Arguments:
lActionVerb - The action verb in long format.
lActionType - The action type
Return Value:
If found, then the CMemberAD object pointer is return. It will return NULl
if the given action is not registered or this operation can't be completed.
Notes:
*/
CMemberAD*
CSsrMemberAccess::GetActionDataObject (
IN SsrActionVerb lActionVerb,
IN LONG lActionType
)
{
CActionType at(lActionVerb, lActionType);
MapMemberAD::iterator it = m_mapMemAD.find(at);
MapMemberAD::iterator itEnd = m_mapMemAD.end();
if (it != itEnd)
{
CMemberAD * pAD = (*it).second;
return pAD;
}
return NULL;
}
/*
Routine Description:
Name:
CSsrMemberAccess::MoveOutputFiles
Functionality:
Will move/delete all those output files.
Virtual:
no.
Arguments:
bstrActionVerb - the action verb
pwszDirPathSrc - The directory path from which the files will be moved.
pwszDirPathSrc - The directory path to which the files will be moved. This will
be ignored if the action is a delete
bDelete - Flag as whether the action is a move or delete.
bLog - To prevent extraneous logging during restoring (backed up
files), if this is not true, then no logging will occur
Return Value:
Success: S_OK
Failure: various error codes
Notes:
*/
HRESULT
CSsrMemberAccess::MoveOutputFiles (
IN SsrActionVerb lActionVerb,
IN LPCWSTR pwszDirPathSrc,
IN LPCWSTR pwszDirPathDest,
IN bool bDelete,
IN bool bLog
)
{
if (bLog)
{
CComBSTR bstrMsg(L"...");
bstrMsg += m_bstrName;
if (bstrMsg.m_str != NULL)
{
g_fblog.LogString(bstrMsg);
}
else
{
return E_OUTOFMEMORY;
}
}
if (lActionVerb == ActionInvalid ||
pwszDirPathSrc == NULL ||
pwszDirPathDest == NULL && !bDelete )
{
return E_INVALIDARG;
}
//
// output files are the transformation results. So, we need
// the transformation result action data, which has the (xsl, output)
// file pairs
//
//
// find the action data for the given action
//
CActionType at(lActionVerb, SSR_ACTION_PREPARE);
MapMemberAD::iterator it = m_mapMemAD.find(at);
HRESULT hr = S_OK;
//
// since we will continue the cleanup in case of errors
// we will return the last error
//
HRESULT hrLastError = S_OK;
if (it != m_mapMemAD.end())
{
CMemberAD * pAD = (*it).second;
_ASSERT(pAD != NULL);
int iProcCount = pAD->GetProcedureCount();
//
// Each member (CMemberAD) may have multiple procedures for this action
//
for (int iProcIndex = 0; iProcIndex < iProcCount; iProcIndex++)
{
const CSsrProcedure * pProc = pAD->GetProcedure(iProcIndex);
_ASSERT(pProc != NULL);
int iFilePairsCount = pProc->GetFilePairCount();
CSsrFilePair * pFilePair;
//
// each procedure may contain multiple file pairs
//
for (int iFPIndex = 0; iFPIndex < iFilePairsCount; iFPIndex++)
{
pFilePair = pProc->GetFilePair(iFPIndex);
_ASSERT(pFilePair != NULL);
//
// if no second file (which is the result file) or the
// second file is a static file, then don't bother to move them
//
if ( pFilePair->GetSecond() == NULL || pFilePair->IsStatic() )
{
continue;
}
//
// move/delete this file
//
CComBSTR bstrSrcFullPath(pwszDirPathSrc);
bstrSrcFullPath += L"\\";
bstrSrcFullPath += pFilePair->GetSecond();
if (bstrSrcFullPath.m_str == NULL)
{
return E_OUTOFMEMORY;
}
if (bDelete)
{
::DeleteFile(bstrSrcFullPath);
}
else
{
CComBSTR bstrDestFullPath(pwszDirPathDest);
bstrDestFullPath += L"\\";
bstrDestFullPath += pFilePair->GetSecond();
if (bstrDestFullPath.m_str == NULL)
{
return E_OUTOFMEMORY;
}
::MoveFile(bstrSrcFullPath, bstrDestFullPath);
}
DWORD dwErrorCode = GetLastError();
if (dwErrorCode != ERROR_SUCCESS &&
dwErrorCode != ERROR_FILE_NOT_FOUND)
{
hr = HRESULT_FROM_WIN32(dwErrorCode);
//
// we will continue to delete the others. But log it
//
if (bLog)
{
hrLastError = hr;
g_fblog.LogFeedback(SSR_FB_ERROR_FILE_DEL | FBLog_Log,
hrLastError,
bstrSrcFullPath,
g_dwResNothing
);
}
}
}
}
}
return hrLastError;
}
DWORD
CSsrMemberAccess::GetActionCost (
IN SsrActionVerb lActionVerb,
IN LONG lActionType
)const
{
CActionType at(lActionVerb, lActionType);
MapMemberAD::iterator it = m_mapMemAD.find(at);
DWORD dwSteps = 0;
if (it != m_mapMemAD.end())
{
CMemberAD * pAD = (*it).second;
_ASSERT(pAD != NULL);
for (int i = 0; i < pAD->GetProcedureCount(); i++)
{
const CSsrProcedure * pProc = pAD->GetProcedure(i);
if (pProc->IsDefaultProcedure())
{
//
// each file pair will count as two steps
//
dwSteps += 2 * pProc->GetFilePairCount();
}
else
{
//
// we have to consult with the custom member
//
CComPtr<ISsrMember> srpCusMember;
GUID clsID;
HRESULT hr = ::CLSIDFromProgID(pProc->GetProgID(), &clsID);
if (S_OK == hr)
{
hr = ::CoCreateInstance(clsID,
NULL,
CLSCTX_INPROC_SERVER,
IID_ISsrMember,
(LPVOID*)&srpCusMember
);
}
if (SUCCEEDED(hr))
{
LONG lCost = 0;
hr = srpCusMember->get_ActionCost(SsrPGetActionVerbString(lActionVerb),
lActionType,
SSR_ACTION_COST_STEPS,
&lCost
);
if (SUCCEEDED(hr))
{
dwSteps += lCost;
}
}
}
}
}
return dwSteps;
}
/*
Routine Description:
Name:
CMemberAD::CMemberAD
Functionality:
Constructor.
Virtual:
no.
Arguments:
lActionVerb - The verb of the action.
lActionType - The type of the action
Return Value:
None
Notes:
*/
CMemberAD::CMemberAD (
IN SsrActionVerb lActionVerb,
IN LONG lActionType
) : m_AT(lActionVerb, lActionType)
{
}
/*
Routine Description:
Name:
CMemberAD::~CMemberAD
Functionality:
destructor. This will clean up our map which contains BSTRs and VARIANTs,
both of which are heap objects.
Virtual:
no.
Arguments:
None.
Return Value:
None
Notes:
*/
CMemberAD::~CMemberAD()
{
for (ULONG i = 0; i < m_vecProcedures.size(); i++)
{
delete m_vecProcedures[i];
}
m_vecProcedures.clear();
}
/*
Routine Description:
Name:
CMemberAD::LoadAD
Functionality:
Will create an a action data object pertaining to a
particular member and an action name.
Virtual:
no.
Arguments:
pActionNode - The SsrAction node
ppMAD - The out parameter that receives the
heap object created by this function
Return Value:
Success: S_OK if there are concrete action data loaded
and in that case the out paramter ppMAD will
point to the heap object. Otherwise, *ppMAD == NULL;
Failure: various error codes.
Notes:
2. Caller is responsible for releaseing the CMemberAD
object passed back by the function.
*/
HRESULT
CMemberAD::LoadAD (
IN LPCWSTR pwszMemberName,
IN IXMLDOMNode * pActionNode,
IN LPCWSTR pwszProgID,
OUT CMemberAD ** ppMAD
)
{
if (ppMAD == NULL)
{
return E_INVALIDARG;
}
*ppMAD = NULL;
if (pActionNode == NULL)
{
return E_INVALIDARG;
}
CComPtr<IXMLDOMNamedNodeMap> srpAttr;
HRESULT hr = pActionNode->get_attributes(&srpAttr);
//
// we must have attributes
//
if (FAILED(hr))
{
return hr;
}
CComBSTR bstrActionName, bstrActionType;
LONG lActionType;
//
// ActionName and ActionType are mandatory attributes
//
hr = SsrPGetBSTRAttrValue(srpAttr, g_bstrAttrActionName, &bstrActionName);
if (FAILED(hr))
{
return hr;
}
SsrActionVerb lActionVerb = SsrPGetActionVerbFromString(bstrActionName);
if (lActionVerb == ActionInvalid)
{
return E_SSR_INVALID_ACTION_VERB;
}
hr = SsrPGetBSTRAttrValue(srpAttr, g_bstrAttrActionType, &bstrActionType);
if (FAILED(hr))
{
return hr;
}
if (_wcsicmp(bstrActionType, g_pwszPrepare) == 0)
{
lActionType = SSR_ACTION_PREPARE;
}
else
{
_ASSERT(_wcsicmp(bstrActionType, g_pwszApply) == 0);
lActionType = SSR_ACTION_APPLY;
}
*ppMAD = new CMemberAD(lActionVerb, lActionType);
if (*ppMAD == NULL)
{
return E_OUTOFMEMORY;
}
//
// now, we need to load the each individual procedure
//
bool bLoaded = false;
if (SUCCEEDED(hr))
{
CComPtr<IXMLDOMNode> srpProcedure;
hr = pActionNode->get_firstChild(&srpProcedure);
while (SUCCEEDED(hr) && srpProcedure != NULL)
{
CComBSTR bstrName;
srpProcedure->get_nodeName(&bstrName);
bool bDefProc = _wcsicmp(bstrName, g_bstrDefaultProc) == 0;
bool bCusProc = _wcsicmp(bstrName, g_bstrCustomProc) == 0;
//
// we only care about DefaultProc and CustomProc elements
//
if ( bDefProc || bCusProc )
{
CSsrProcedure * pNewProc = NULL;
if (SUCCEEDED(hr))
{
hr = CSsrProcedure::StaticLoadProcedure(srpProcedure, bDefProc, pwszProgID, &pNewProc);
}
if (SUCCEEDED(hr))
{
//
// give it to our vector
//
(*ppMAD)->m_vecProcedures.push_back(pNewProc);
bLoaded = true;
}
else
{
//
// will quit loading
//
g_fblog.LogFeedback(SSR_FB_ERROR_LOAD_MEMBER | FBLog_Log,
hr,
pwszMemberName,
IDS_XML_LOADING_PROCEDURE
);
break;
}
}
CComPtr<IXMLDOMNode> srpNext;
hr = srpProcedure->get_nextSibling(&srpNext);
srpProcedure.Release();
srpProcedure = srpNext;
}
}
//
// either failed or loaded nothing
//
if (FAILED(hr) || !bLoaded)
{
delete *ppMAD;
*ppMAD = NULL;
}
return SUCCEEDED(hr) ? S_OK : hr;
}
CSsrProcedure::CSsrProcedure()
: m_bIsDefault(true)
{
}
CSsrProcedure::~CSsrProcedure()
{
for (ULONG i = 0; i < m_vecFilePairs.size(); i++)
{
delete m_vecFilePairs[i];
}
m_vecFilePairs.clear();
}
HRESULT
CSsrProcedure::StaticLoadProcedure (
IN IXMLDOMNode * pNode,
IN bool bDefProc,
IN LPCWSTR pwszProgID,
OUT CSsrProcedure ** ppNewProc
)
{
if (ppNewProc == NULL)
{
return E_INVALIDARG;
}
*ppNewProc = NULL;
if (pNode == NULL)
{
return E_INVALIDARG;
}
*ppNewProc = new CSsrProcedure;
if (*ppNewProc == NULL)
{
return E_OUTOFMEMORY;
}
//
// let's determine if this procedure is a default proc or custom proc.
// That is determined by the tag name.
//
CComPtr<IXMLDOMNamedNodeMap> srpAttr;
CComBSTR bstrTagName;
HRESULT hr = S_OK;
if (!bDefProc)
{
//
// we are loding custom proc
//
(*ppNewProc)->m_bIsDefault = false;
//
// in this case, you should have no more than the ProgID that we care
//
hr = pNode->get_attributes(&srpAttr);
_ASSERT(srpAttr);
CComBSTR bstrProgID;
if (SUCCEEDED(hr))
{
//
// will try to get the ProgID attribute, may fail and we
// don't care if it does
//
SsrPGetBSTRAttrValue(srpAttr, g_bstrAttrProgID, &bstrProgID);
}
if (bstrProgID != NULL)
{
(*ppNewProc)->m_bstrProgID = bstrProgID;
}
else
{
(*ppNewProc)->m_bstrProgID = pwszProgID;
}
}
else
{
//
// for default procedures, we should have a list of TransformFiles or ScriptFiles
// elements. But we will create for both type of elements a CSsrFilePair object
// and put it in the m_vecFilePairs vector
//
//
// for that purpose, we need to traverse through the in sequential order
// the TransformFiles and ScriptFiles elements
//
CComPtr<IXMLDOMNode> srpFilePairNode;
CComPtr<IXMLDOMNode> srpNext;
hr = pNode->get_firstChild(&srpFilePairNode);
while (SUCCEEDED(hr) && srpFilePairNode != NULL)
{
//
// Get the tag name. Empty the smart pointer so that we can re-use it
//
CComPtr<IXMLDOMNamedNodeMap> srpFilePairAttr;
bstrTagName.Empty();
hr = srpFilePairNode->get_nodeName(&bstrTagName);
_ASSERT(SUCCEEDED(hr));
if (FAILED(hr))
{
break;
}
hr = srpFilePairNode->get_attributes(&srpFilePairAttr);
_ASSERT(srpAttr);
//
// we will ignore all other elements because we only know
// two possible types of elements: TransformInfo and ScriptInfo
//
if (_wcsicmp(bstrTagName, g_bstrTransformInfo) == 0)
{
//
// if it is a TransformFiles element, then, we really have a pair
// (xsl, script)
//
//
// we have potentially both TemplateFile and ResultFile attributes
//
CComBSTR bstrXsl, bstrResult;
hr = SsrPGetBSTRAttrValue(srpFilePairAttr, g_bstrAttrTemplateFile, &bstrXsl);
_ASSERT(SUCCEEDED(hr));
//
// may not have this one
//
SsrPGetBSTRAttrValue(srpFilePairAttr, g_bstrAttrResultFile, &bstrResult);
if (SUCCEEDED(hr))
{
//
// any result file is used as a result file (funny?), which means that the
// file is created during the process of transformation
//
CSsrFilePair * pNewFilePair = new CSsrFilePair(bstrXsl, bstrResult);
if (pNewFilePair != NULL)
{
(*ppNewProc)->m_vecFilePairs.push_back(pNewFilePair);
}
else
{
hr = E_OUTOFMEMORY;
}
}
}
else if (_wcsicmp(bstrTagName, g_bstrScriptInfo) == 0)
{
//
// we will only have ScriptFile and usage attributes
//
CComBSTR bstrAttr;
CComBSTR bstrScript;
hr = SsrPGetBSTRAttrValue(srpFilePairAttr, g_bstrAttrScriptFile, &bstrScript);
_ASSERT(SUCCEEDED(hr));
if (SUCCEEDED(hr))
{
//
// may not have this one, but in that case, it is defaulted
// to "Launch". Since an executable file will be launched,
// it's safer to assume that it is not an executable file.
// Likewise, since non-static file will be removed during
// preparation, we'd better assume that it is a static.
//
bool bIsExecutable = false;
bool bIsStatic = true;
//
// Get the IsExecutable attribute
//
bstrAttr.Empty();
if ( SUCCEEDED(SsrPGetBSTRAttrValue(srpFilePairAttr,
g_bstrAttrIsExecutable,
&bstrAttr)) &&
bstrAttr != NULL )
{
//
// err on the side of false is safer
//
if (_wcsicmp(bstrAttr, g_bstrTrue) != 0)
{
bIsExecutable = false;
}
else
{
bIsExecutable = true;
}
}
//
// Get the IsStatic attribute.
//
bstrAttr.Empty();
if ( SUCCEEDED(SsrPGetBSTRAttrValue(srpFilePairAttr,
g_bstrAttrIsStatic,
&bstrAttr)) &&
bstrAttr != NULL )
{
if (_wcsicmp(bstrAttr, g_bstrFalse) == 0)
{
bIsStatic = false;
}
}
//
// the script may be a result of a preparation, or a script file
// to launch during the action
//
CSsrFilePair * pNewFilePair = new CSsrFilePair(NULL, bstrScript, bIsStatic, bIsExecutable);
if (pNewFilePair != NULL)
{
(*ppNewProc)->m_vecFilePairs.push_back(pNewFilePair);
}
else
{
hr = E_OUTOFMEMORY;
}
}
}
if (FAILED(hr))
{
break;
}
//
// if it is a ScriptFiles element, then, it only has the script file
//
hr = srpFilePairNode->get_nextSibling(&srpNext);
srpFilePairNode = srpNext;
srpNext.Release();
}
}
if (FAILED(hr) && *ppNewProc != NULL)
{
delete *ppNewProc;
*ppNewProc = NULL;
}
return SUCCEEDED(hr) ? S_OK : hr;
}