windows-nt/Source/XPSP1/NT/net/upnp/tools/scpdgen/scpdgen.cpp

1148 lines
37 KiB
C++
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1997.
//
// File: S C P D G E N . C P P
//
// Contents: Functions that generates scpd for upnp service
//
// Notes:
//
// Author: tongl 7 December 1999
//
//----------------------------------------------------------------------------
#include "pch.h"
#pragma hdrstop
#include "stdio.h"
#include "ncstring.h"
#include "oleauto.h"
#include "setupapi.h"
#include "util.h"
struct ARG_DATA
{
// argument to an action
TCHAR szArg[256];
// related state variable
TCHAR szVariable[256];
};
struct ARG_LIST
{
DWORD cArgs;
ARG_DATA rgArguments[MAX_ACTION_ARGUMENTS];
};
HRESULT HrCreateScpdNode(IN IXMLDOMDocument * pScpdDoc,
OUT IXMLDOMElement ** ppScpdNode);
HRESULT HrCreateStateVariableNode(IN LPTSTR szVariableLine,
IN IXMLDOMDocument * pScpdDoc,
OUT IXMLDOMElement ** ppVariableNode);
HRESULT HrCreateServiceStateTableNode(IN HINF hinf,
IN IXMLDOMDocument * pScpdDoc,
OUT IXMLDOMElement ** ppSSTNode);
HRESULT HrCreateActionNode(IN HINF hinf,
IN LPTSTR szActionLine,
IN IXMLDOMDocument * pScpdDoc,
OUT IXMLDOMElement ** ppActionNode);
HRESULT HrCreateActionListNode(IN HINF hinf,
IN IXMLDOMDocument * pScpdDoc,
OUT IXMLDOMElement ** ppActionListNode);
BOOL IsStandardOperation(TCHAR * szOpName, DWORD * pnArgs, DWORD * pnConsts);
//
// Create scpd doc for service from the config file and save to
// specified destination
//
EXTERN_C
VOID
__cdecl
wmain (
IN INT argc,
IN PCWSTR argv[])
{
HRESULT hr = S_OK;
if (argc != 3)
{
_tprintf(TEXT("\nUsage: \n %s\n\n"),
TEXT("<Service INF file>, <SCPD xml file name and path>"));
return;
};
TCHAR szSvcConfigFile[MAX_PATH];
WszToTszBuf(szSvcConfigFile, argv[1], MAX_PATH);
LPCWSTR pszScpdFileWithPath = argv[2];
hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
if (FAILED(hr))
{
TraceError("CoInitializeEx", hr);
return;
}
IXMLDOMDocument *pScpdDoc = NULL;
// Create a new document object
hr = CoCreateInstance(CLSID_DOMDocument30,
NULL,
CLSCTX_INPROC_SERVER,
IID_IXMLDOMDocument,
(void **) &pScpdDoc);
if (SUCCEEDED(hr))
{
hr = pScpdDoc->put_preserveWhiteSpace(VARIANT_TRUE);
if (S_OK == hr)
{
// Build <?xml version="1.0"?>
IXMLDOMProcessingInstruction * piVersion = NULL;
BSTR bstrTarget = SysAllocString(L"xml");
if (bstrTarget)
{
BSTR bstrData = SysAllocString(L"version=\"1.0\"");
if (bstrData)
{
hr = pScpdDoc->createProcessingInstruction(
bstrTarget, bstrData, &piVersion);
if (SUCCEEDED(hr))
{
// Append the <version> element to the document.
hr = pScpdDoc->appendChild(piVersion, NULL);
piVersion->Release();
if (FAILED(hr))
{
TraceError("Failed to append <version> to document.", hr);
}
SysFreeString(bstrTarget);
SysFreeString(bstrData);
}
}
else
{
hr = E_OUTOFMEMORY;
}
}
else
{
hr = E_OUTOFMEMORY;
}
// Build <scpd> element
VARIANT vNULL;
vNULL.vt = VT_EMPTY;
IXMLDOMElement * pScpdNode = NULL;
hr = HrCreateScpdNode(pScpdDoc, &pScpdNode);
if (SUCCEEDED(hr))
{
// open the config file
HINF hinf = NULL;
UINT unErrorLine;
hr = HrSetupOpenConfigFile(szSvcConfigFile, &unErrorLine, &hinf);
if (S_OK == hr)
{
Assert(IsValidHandle(hinf));
// Build <serviceStateTable> element
IXMLDOMElement * pSSTNode = NULL;
hr = HrCreateServiceStateTableNode(hinf, pScpdDoc, &pSSTNode);
if (SUCCEEDED(hr))
{
Assert(pSSTNode);
hr = pScpdNode->insertBefore(pSSTNode,
vNULL,
NULL);
pSSTNode->Release();
if (FAILED(hr))
{
TraceError("Failed to insert <serviceStateTable> element", hr);
}
else
{
// Build <actionList> element
IXMLDOMElement * pActionListNode = NULL;
hr = HrCreateActionListNode(hinf, pScpdDoc, &pActionListNode);
if (SUCCEEDED(hr))
{
Assert(pActionListNode);
hr = pScpdNode->insertBefore(pActionListNode,
vNULL,
NULL);
pActionListNode->Release();
if (FAILED(hr))
{
TraceError("Failed to insert <actionList> element", hr);
}
}
}
}
SetupCloseInfFileSafe(hinf);
}
else
{
TraceTag(ttidUpdiag, "Failed to open file %s, line = %d",
szSvcConfigFile, unErrorLine);
}
// Append the <scpd> element to the document.
if (SUCCEEDED(hr))
{
hr = pScpdDoc->appendChild(pScpdNode, NULL);
pScpdNode->Release();
if (FAILED(hr))
{
TraceError("Failed to append <scpd> element to document.", hr);
}
}
}
else
{
TraceError("Failed to create <scpd> element", hr);
}
if (SUCCEEDED(hr))
{
// Persist the xml document
VARIANT vFileName;
vFileName.vt = VT_BSTR;
V_BSTR(&vFileName) = SysAllocString(pszScpdFileWithPath);
hr = pScpdDoc->save(vFileName);
VariantClear(&vFileName);
}
pScpdDoc->Release();
}
}
else
{
TraceError("Failed to create XML DOM Document object", hr);
}
CoUninitialize();
}
//
// Create the <scpd> note that will include a serviceStateTable and
// an actionList
//
HRESULT HrCreateScpdNode(IN IXMLDOMDocument * pScpdDoc,
OUT IXMLDOMElement ** ppScpdNode)
{
HRESULT hr = S_OK;
Assert(ppScpdNode);
*ppScpdNode = NULL;
IXMLDOMElement * pScpdNode = NULL;
BSTR bstrElementName = SysAllocString(L"scpd");
if (bstrElementName)
{
hr = pScpdDoc->createElement(bstrElementName, &pScpdNode);
if (SUCCEEDED(hr))
{
// set the xmlns attribute
BSTR bstrAttrName = SysAllocString(L"xmlns");
if (bstrAttrName)
{
VARIANT vValue;
vValue.vt = VT_BSTR;
V_BSTR(&vValue) = SysAllocString(L"x-schema:scpdl-schema.xml");
hr = pScpdNode->setAttribute(bstrAttrName, vValue);
SysFreeString(bstrAttrName);
VariantClear(&vValue);
}
else
{
hr = E_OUTOFMEMORY;
}
if (SUCCEEDED(hr))
{
*ppScpdNode = pScpdNode;
pScpdNode->AddRef();
}
else
{
TraceError("HrCreateScpdNode: Failed to set xmlns attribute", hr);
}
pScpdNode->Release();
}
else
{
TraceError("HrCreateScpdNode: Failed to create <scpd> element", hr);
}
SysFreeString(bstrElementName);
}
else
{
hr = E_OUTOFMEMORY;
TraceError("HrCreateScpdNode: Failed to allocate BSTR for element name", hr);
}
TraceError("HrCreateScpdNode", hr);
return hr;
}
HRESULT HrCreateServiceStateTableNode(IN HINF hinf,
IN IXMLDOMDocument * pScpdDoc,
OUT IXMLDOMElement ** ppSSTNode)
{
HRESULT hr = S_OK;
Assert(ppSSTNode);
*ppSSTNode = NULL;
IXMLDOMElement * pSSTNode = NULL;
BSTR bstrElementName = SysAllocString(L"serviceStateTable");
if (bstrElementName)
{
hr = pScpdDoc->createElement(bstrElementName, &pSSTNode);
if (SUCCEEDED(hr))
{
// get the [StateTable] section
INFCONTEXT ctx;
hr = HrSetupFindFirstLine(hinf, TEXT("StateTable"), NULL, &ctx);
if (S_OK == hr)
{
// loop through [StateTable] section and create stateVariable's
TCHAR szKey[LINE_LEN]; // LINE_LEN defined in setupapi.h as 256
TCHAR szVariableLine[LINE_LEN];
IXMLDOMElement * pVariableNode = NULL;
VARIANT vNULL;
vNULL.vt = VT_EMPTY;
do
{
// Retrieve a line from the ActionSet section
hr = HrSetupGetStringField(ctx,0,szKey,celems(szKey),NULL);
if(S_OK == hr)
{
// varify this is a "Variable"
szKey[celems(szKey)-1] = L'\0';
if (lstrcmpi(szKey, TEXT("Variable")))
{
TraceTag(ttidUpdiag, "Wrong key in the StateTable section: %s", szKey);
continue;
}
// get the line text
hr = HrSetupGetLineText(ctx, szVariableLine, celems(szVariableLine),
NULL);
if (S_OK == hr)
{
// Add variable in this line
hr = HrCreateStateVariableNode(szVariableLine, pScpdDoc, &pVariableNode);
if (SUCCEEDED(hr))
{
Assert(pVariableNode);
hr = pSSTNode->insertBefore(pVariableNode,
vNULL,
NULL);
pVariableNode->Release();
}
}
}
}
while (S_OK == (hr = HrSetupFindNextLine(ctx, &ctx)));
if (hr == S_FALSE)
{
// S_FALSE will terminate the loop successfully, so convert it to S_OK
// here.
hr = S_OK;
}
if (S_OK == hr)
{
*ppSSTNode = pSSTNode;
pSSTNode->AddRef();
}
}
else
{
TraceError("HrCreateScpdNode: [StateTable] section not found in inf", hr);
}
}
else
{
TraceError("HrCreateScpdNode: Failed to create <serviceStateTable> element", hr);
}
SysFreeString(bstrElementName);
}
else
{
hr = E_OUTOFMEMORY;
TraceError("HrCreateServiceStateTableNode: Failed to allocate BSTR for element name", hr);
}
TraceError("HrCreateServiceStateTableNode", hr);
return hr;
}
HRESULT HrAddElementWithText(IXMLDOMDocument * pDoc,
IXMLDOMElement * pParentNode,
LPTSTR szElementName,
LPTSTR szElementText)
{
HRESULT hr = S_OK;
IXMLDOMElement * pNewNode = NULL;
VARIANT vNull;
vNull.vt = VT_EMPTY;
BSTR bstrElementName = NULL;
BSTR bstrTextValue = NULL;
WCHAR * wszElementName = WszFromTsz(szElementName);
WCHAR * wszElementText = WszFromTsz(szElementText);
if (!wszElementName || !wszElementText)
{
hr = E_OUTOFMEMORY;
}
else
{
bstrElementName = SysAllocString(wszElementName);
bstrTextValue = SysAllocString(wszElementText);
if (!bstrElementName || !bstrTextValue)
{
hr = E_OUTOFMEMORY;
}
delete wszElementName;
delete wszElementText;
}
if (SUCCEEDED(hr))
{
hr = pDoc->createElement(bstrElementName, &pNewNode);
if (SUCCEEDED(hr))
{
IXMLDOMText * pText = NULL;
hr = pDoc->createTextNode(bstrTextValue, &pText);
if (SUCCEEDED(hr))
{
hr = pNewNode->insertBefore(pText, vNull, NULL);
if (FAILED(hr))
{
TraceError("HrAddElementWithText: Failed to insert text node", hr);
}
pText->Release();
}
else
{
TraceError("HrAddElementWithText: Failed to create text node", hr);
}
if (SUCCEEDED(hr))
{
hr = pParentNode->insertBefore(pNewNode, vNull, NULL);
if (FAILED(hr))
{
TraceError("HrAddElementWithText: Failed to insert new node", hr);
}
}
pNewNode->Release();
}
else
{
TraceError("HrAddElementWithText: Could not create new element", hr);
}
SysFreeString(bstrElementName);
SysFreeString(bstrTextValue);
}
TraceError("HrAddElementWithText", hr);
return hr;
}
BOOL fIsValidDataType(LPTSTR szBuf)
{
return ((lstrcmpi(szBuf, TEXT("number")) ==0) ||
(lstrcmpi(szBuf, TEXT("string")) ==0) ||
(lstrcmpi(szBuf, TEXT("dateTime")) ==0) ||
(lstrcmpi(szBuf, TEXT("boolean")) ==0) ||
(lstrcmpi(szBuf, TEXT("ByteBlock")) ==0));
}
HRESULT HrAddAllowedValueNode( IXMLDOMDocument * pDoc,
IXMLDOMElement * pVariableNode,
LPTSTR szBuf)
{
HRESULT hr = S_OK;
Assert(*szBuf == '(');
szBuf++;
IXMLDOMElement * pAllowedValueNode = NULL;
BSTR bstrElementName;
// we assume that ".." specifies a range, otherwise it's a comma separated
// list of allowed values
TCHAR * pChar = _tcsstr(szBuf, TEXT(".."));
if (pChar)
{
// we have a range
// BUGBUG: we should check if data type of the min, max & step
// matches the variable type
TCHAR * szMin, * szMax, * szStep;
szMin = szBuf;
*pChar = '\0';
szMax = pChar+2;
pChar = _tcschr(szMax, TEXT(','));
if (pChar)
{
*pChar = '\0';
szStep = ++pChar;
pChar = _tcschr(szStep, TEXT(')'));
if (pChar)
{
*pChar = '\0';
bstrElementName = SysAllocString(L"allowedValueRange");
if (bstrElementName)
{
hr = pDoc->createElement(bstrElementName, &pAllowedValueNode);
if (SUCCEEDED(hr))
{
hr = HrAddElementWithText(pDoc, pAllowedValueNode, TEXT("minimum"), szMin);
if (SUCCEEDED(hr))
{
hr = HrAddElementWithText(pDoc, pAllowedValueNode, TEXT("maximum"), szMax);
if (SUCCEEDED(hr))
{
hr = HrAddElementWithText(pDoc, pAllowedValueNode, TEXT("step"), szStep);
}
}
}
SysFreeString(bstrElementName);
}
else
{
hr = E_OUTOFMEMORY;
}
}
else
{
TraceTag(ttidUpdiag, "HrAddAllowedValueNode: missing closing )");
hr = E_INVALIDARG;
}
}
else
{
TraceTag(ttidUpdiag, "HrAddAllowedValueNode: step not specified");
hr = E_INVALIDARG;
}
}
else
{
// we have a list of allowed values
pChar = _tcschr(szBuf, TEXT(')'));
if (pChar)
{
*pChar = '\0';
if (lstrlen(szBuf))
{
bstrElementName = SysAllocString(L"allowedValueList");
if (bstrElementName)
{
hr = pDoc->createElement(bstrElementName, &pAllowedValueNode);
if (SUCCEEDED(hr))
{
while ((S_OK ==hr) && (pChar = _tcschr(szBuf, TEXT(','))))
{
*pChar = '\0';
hr = HrAddElementWithText(pDoc, pAllowedValueNode,
TEXT("allowedValue"), szBuf);
szBuf = ++pChar;
}
// add the last one
if (*szBuf)
{
hr = HrAddElementWithText(pDoc, pAllowedValueNode,
TEXT("allowedValue"), szBuf);
}
else
{
TraceTag(ttidUpdiag, "HrAddAllowedValueNode: invalid syntax");
hr = E_INVALIDARG;
}
}
SysFreeString(bstrElementName);
}
else
{
hr = E_OUTOFMEMORY;
}
}
}
else
{
TraceTag(ttidUpdiag, "HrAddAllowedValueNode: missing closing )");
hr = E_INVALIDARG;
}
}
if (pAllowedValueNode && (S_OK == hr))
{
// append the allowed value node to "stateVariable"
VARIANT vNull;
vNull.vt = VT_EMPTY;
hr = pVariableNode->insertBefore(pAllowedValueNode, vNull, NULL);
}
TraceError("HrAddAllowedValueRangeNode" , hr);
return hr;
}
HRESULT HrCreateStateVariableNode(IN LPTSTR szVariableLine,
IN IXMLDOMDocument * pScpdDoc,
OUT IXMLDOMElement ** ppVariableNode)
{
HRESULT hr = S_OK;
Assert(ppVariableNode);
*ppVariableNode = NULL;
IXMLDOMElement * pVariableNode = NULL;
BSTR bstrElementName = SysAllocString(L"stateVariable");
if (bstrElementName)
{
hr = pScpdDoc->createElement(bstrElementName, &pVariableNode);
if (SUCCEEDED(hr))
{
TCHAR szBuf[MAX_PATH];
if (fGetNextField(&szVariableLine, szBuf))
{
hr = HrAddElementWithText(pScpdDoc, pVariableNode, TEXT("name"), szBuf);
if (SUCCEEDED(hr))
{
if (fGetNextField(&szVariableLine, szBuf))
{
if (fIsValidDataType(szBuf))
{
hr = HrAddElementWithText(pScpdDoc, pVariableNode,
TEXT("dataType"), szBuf);
// AllowedValueRange is optional
if (SUCCEEDED(hr) && fGetNextField(&szVariableLine, szBuf))
{
hr = HrAddAllowedValueNode(pScpdDoc, pVariableNode, szBuf);
}
if (SUCCEEDED(hr) && fGetNextField(&szVariableLine, szBuf))
{
hr = HrAddElementWithText(pScpdDoc, pVariableNode,
TEXT("defaultValue"), szBuf);
}
}
else
{
hr = E_INVALIDARG;
TraceError("HrCreateStateVariableNode: invalid data type specified", hr);
}
}
else
{
hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
}
}
}
else
{
hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
}
if (S_OK == hr)
{
*ppVariableNode = pVariableNode;
pVariableNode->AddRef();
}
}
else
{
TraceError("HrCreateStateVariableNode: Failed to create <stateVariable> element", hr);
}
SysFreeString(bstrElementName);
}
else
{
hr = E_OUTOFMEMORY;
TraceError("HrCreateStateVariableNode: Failed to allocate BSTR for element name", hr);
}
TraceError("HrCreateStateVariableNode", hr);
return hr;
}
HRESULT HrCreateActionListNode(IN HINF hinf,
IN IXMLDOMDocument * pScpdDoc,
OUT IXMLDOMElement ** ppActionListNode)
{
HRESULT hr = S_OK;
Assert(ppActionListNode);
*ppActionListNode = NULL;
IXMLDOMElement * pActionListNode = NULL;
BSTR bstrElementName = SysAllocString(L"actionList");
if (bstrElementName)
{
hr = pScpdDoc->createElement(bstrElementName, &pActionListNode);
if (SUCCEEDED(hr))
{
// get the [ActionSet] section
INFCONTEXT ctx;
hr = HrSetupFindFirstLine(hinf, TEXT("ActionSet"), NULL, &ctx);
if (S_OK == hr)
{
// loop through [ActionSet] section and create actions
TCHAR szKey[LINE_LEN]; // LINE_LEN defined in setupapi.h as 256
TCHAR szActionLine[LINE_LEN];
IXMLDOMElement * pActionNode = NULL;
VARIANT vNULL;
vNULL.vt = VT_EMPTY;
do
{
// Retrieve a line from the ActionSet section
hr = HrSetupGetStringField(ctx,0,szKey,celems(szKey),NULL);
if(S_OK == hr)
{
// varify this is a "Action"
szKey[celems(szKey)-1] = L'\0';
if (lstrcmpi(szKey, TEXT("Action")))
{
TraceTag(ttidUpdiag, "Wrong key in the ActionSet section: %s", szKey);
continue;
}
// get the line text
hr = HrSetupGetLineText(ctx, szActionLine, celems(szActionLine),
NULL);
if (S_OK == hr)
{
// Add action in this line
hr = HrCreateActionNode(hinf, szActionLine, pScpdDoc, &pActionNode);
if (SUCCEEDED(hr))
{
Assert(pActionNode);
hr = pActionListNode->insertBefore( pActionNode,
vNULL,
NULL);
pActionNode->Release();
}
}
}
}
while (S_OK == (hr = HrSetupFindNextLine(ctx, &ctx)));
if (hr == S_FALSE)
{
// S_FALSE will terminate the loop successfully, so convert it to S_OK
// here.
hr = S_OK;
}
if (S_OK == hr)
{
*ppActionListNode = pActionListNode;
pActionListNode->AddRef();
}
}
else
{
TraceError("HrCreateScpdNode: [ActionSet] not found in service inf", hr);
}
}
else
{
TraceError("HrCreateScpdNode: Failed to create <actionList> element", hr);
}
SysFreeString(bstrElementName);
}
else
{
hr = E_OUTOFMEMORY;
TraceError("HrCreateScpdNode: Failed to allocate BSTR for element name", hr);
}
TraceError("HrCreateActionListNode", hr);
return hr;
}
//
// Construct the list of arguments and related state variable
// for each argument
//
HRESULT HrGetArgumentList(IN HINF hinf,
IN LPTSTR szActionName,
IN LPTSTR szActionArgList,
OUT ARG_LIST * pargList)
{
HRESULT hr = S_OK;
BOOL fNamedArgs = FALSE;
if (szActionArgList)
{
fNamedArgs = !!lstrlen(szActionArgList);
}
DWORD dwNum = 1;
// Loop over the list of operations for this action
INFCONTEXT ctx;
hr = HrSetupFindFirstLine(hinf, szActionName, NULL, &ctx);
if (S_OK == hr)
{
do
{
TCHAR szKey[LINE_LEN]; // LINE_LEN defined in setupapi.h as 256
TCHAR szOpLine[LINE_LEN];
// Retrieve a line from the Action
hr = HrSetupGetStringField(ctx, 0, szKey, celems(szKey), NULL);
if(S_OK == hr)
{
// varify this is an "Operation"
szKey[celems(szKey)-1] = L'\0';
if (lstrcmpi(szKey, TEXT("Operation")))
{
TraceTag(ttidUpdiag, "ERROR! HrGetRelatedVariableList: Wrong key in the Operation section: %s", szKey);
continue;
}
hr = HrSetupGetLineText(ctx, szOpLine, celems(szOpLine), NULL);
if (S_OK == hr)
{
// Get the affected variables in this operation
TCHAR * szRelatedVariable;
TCHAR * pChar = _tcschr(szOpLine, TEXT('('));
if (pChar)
{
*pChar ='\0';
TCHAR * szOpName = szOpLine;
pChar ++;
szRelatedVariable = pChar;
DWORD nArgs;
DWORD nConsts;
if (IsStandardOperation(szOpName, &nArgs, &nConsts))
{
// get the Variable name
if (nArgs+nConsts ==0)
{
pChar = _tcschr(szRelatedVariable, TEXT(')'));
}
else
{
pChar = _tcschr(szRelatedVariable, TEXT(','));
}
if (pChar)
{
*pChar = TEXT('\0');
// BUGBUG: Can we check if the variable is valid ??
for (DWORD iArg =0; iArg < nArgs; iArg++)
{
TCHAR szArgName[256];
*szArgName = '\0';
if (!fNamedArgs)
{
// generate argument name, add to the list
lstrcpy(szArgName, TEXT("Argument_"));
TCHAR szNum[2];
_itot(dwNum, szNum, 10);
lstrcat(szArgName, szNum);
dwNum++;
}
else
{
// use the argument name specified in the inf
pChar = _tcschr(szActionArgList, TEXT(','));
if (pChar)
{
*pChar = '\0';
lstrcpy(szArgName, szActionArgList);
pChar ++;
szActionArgList = pChar;
}
else
{
lstrcpy(szArgName, szActionArgList);
}
}
if (!(*szArgName))
{
TraceTag(ttidUpdiag, "Argument list incomplete!");
hr = E_INVALIDARG;
break;
}
else
{
if (pargList->cArgs < MAX_ACTION_ARGUMENTS)
{
TraceTag(ttidUpdiag, "HrGetArgumentList: action: %s, argument: %s, relatedStateVariable: %s",
szActionName, szArgName, szRelatedVariable);
lstrcpy(pargList->rgArguments[pargList->cArgs].szArg, szArgName);
lstrcpy(pargList->rgArguments[pargList->cArgs].szVariable, szRelatedVariable);
pargList->cArgs++;
}
else
{
TraceTag(ttidUpdiag, "Too many arguments!");
hr = E_INVALIDARG;
break;
}
}
}
}
}
else
{
TraceTag(ttidUpdiag, "ERROR! HrGetArgumentList: unknown operation: %s",
szOpName);
}
}
}
}
}
while (S_OK == (hr = HrSetupFindNextLine(ctx, &ctx)));
}
if (hr == S_FALSE)
{
// S_FALSE will terminate the loop successfully, so convert it to S_OK
// here.
hr = S_OK;
}
TraceError("HrGetArgumentList",hr);
return hr;
}
HRESULT HrAddArgumentNode( IXMLDOMDocument * pDoc,
IXMLDOMElement * pArgumentListNode,
LPTSTR szArgumentName,
LPTSTR szVariableName)
{
HRESULT hr = S_OK;
IXMLDOMElement * pArgumentNode = NULL;
BSTR bstrElementName = SysAllocString(L"argument");
if (bstrElementName)
{
hr = pDoc->createElement(bstrElementName, &pArgumentNode);
if (SUCCEEDED(hr))
{
// name
hr = HrAddElementWithText(pDoc, pArgumentNode,
TEXT("name"), szArgumentName);
if (SUCCEEDED(hr))
{
// relatedStateVariable
hr = HrAddElementWithText(pDoc, pArgumentNode,
TEXT("relatedStateVariable"), szVariableName);
}
}
else
{
TraceTag(ttidUpdiag, "HrAddArgumentNode: failed creating <argument> node");
}
SysFreeString(bstrElementName);
}
else
{
hr = E_OUTOFMEMORY;
}
if (pArgumentNode && (S_OK == hr))
{
// append the argument node to "argumentList"
VARIANT vNull;
vNull.vt = VT_EMPTY;
hr = pArgumentListNode->insertBefore(pArgumentNode, vNull, NULL);
pArgumentNode->Release();
}
TraceError("HrAddArgumentNode", hr);
return hr;
}
HRESULT HrCreateActionNode(IN HINF hinf,
IN LPTSTR szActionLine,
IN IXMLDOMDocument * pDoc,
OUT IXMLDOMElement ** ppActionNode)
{
HRESULT hr = S_OK;
Assert(ppActionNode);
*ppActionNode = NULL;
IXMLDOMElement * pActionNode = NULL;
BSTR bstrAction = SysAllocString(L"action");
if (bstrAction)
{
hr = pDoc->createElement(bstrAction, &pActionNode);
if (SUCCEEDED(hr))
{
TCHAR * szActionName = szActionLine;
TCHAR * szActionArgList = NULL;
TCHAR * pChar = _tcschr(szActionLine, TEXT('('));
if (pChar)
{
*pChar = '\0';
pChar ++;
szActionArgList = pChar;
pChar = _tcschr(szActionArgList, TEXT(')'));
if (pChar)
{
*pChar = '\0';
}
else
{
TraceTag(ttidUpdiag, "HrCreateActionNode: argument list missing closing )");
hr = E_INVALIDARG;
}
}
if (SUCCEEDED(hr))
{
// <name>
hr = HrAddElementWithText(pDoc, pActionNode, TEXT("name"), szActionName);
if (SUCCEEDED(hr))
{
// <argumentList>
ARG_LIST argList;
argList.cArgs = 0;
hr = HrGetArgumentList(hinf, szActionName, szActionArgList, &argList);
if (SUCCEEDED(hr) && (argList.cArgs > 0))
{
IXMLDOMElement * pArgumentListNode = NULL;
BSTR bstrArgumentList = SysAllocString(L"argumentList");
if (bstrArgumentList)
{
hr = pDoc->createElement(bstrArgumentList, &pArgumentListNode);
if (SUCCEEDED(hr))
{
for (DWORD iArg = 0; iArg < argList.cArgs; iArg++)
{
hr = HrAddArgumentNode(pDoc, pArgumentListNode,
argList.rgArguments[iArg].szArg,
argList.rgArguments[iArg].szVariable);
if (FAILED(hr))
break;
}
if (SUCCEEDED(hr))
{
// append the argumentList node to "action"
VARIANT vNull;
vNull.vt = VT_EMPTY;
hr = pActionNode->insertBefore(pArgumentListNode, vNull, NULL);
pArgumentListNode->Release();
}
}
else
{
TraceTag(ttidUpdiag, "HrCreateActionNode: failed creating argument list node");
}
SysFreeString(bstrArgumentList);
}
else
{
hr = E_OUTOFMEMORY;
}
}
}
}
}
else
{
TraceTag(ttidUpdiag, "HrCreateActionNode: Failed to create <action> node.");
}
SysFreeString(bstrAction);
}
else
{
hr = E_OUTOFMEMORY;
}
if (S_OK == hr)
{
*ppActionNode = pActionNode;
pActionNode->AddRef();
}
TraceError("HrCreateActionNode", hr);
return hr;
}