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