Source code of Windows XP (NT5)
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.

1147 lines
37 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1997.
  5. //
  6. // File: S C P D G E N . C P P
  7. //
  8. // Contents: Functions that generates scpd for upnp service
  9. //
  10. // Notes:
  11. //
  12. // Author: tongl 7 December 1999
  13. //
  14. //----------------------------------------------------------------------------
  15. #include "pch.h"
  16. #pragma hdrstop
  17. #include "stdio.h"
  18. #include "ncstring.h"
  19. #include "oleauto.h"
  20. #include "setupapi.h"
  21. #include "util.h"
  22. struct ARG_DATA
  23. {
  24. // argument to an action
  25. TCHAR szArg[256];
  26. // related state variable
  27. TCHAR szVariable[256];
  28. };
  29. struct ARG_LIST
  30. {
  31. DWORD cArgs;
  32. ARG_DATA rgArguments[MAX_ACTION_ARGUMENTS];
  33. };
  34. HRESULT HrCreateScpdNode(IN IXMLDOMDocument * pScpdDoc,
  35. OUT IXMLDOMElement ** ppScpdNode);
  36. HRESULT HrCreateStateVariableNode(IN LPTSTR szVariableLine,
  37. IN IXMLDOMDocument * pScpdDoc,
  38. OUT IXMLDOMElement ** ppVariableNode);
  39. HRESULT HrCreateServiceStateTableNode(IN HINF hinf,
  40. IN IXMLDOMDocument * pScpdDoc,
  41. OUT IXMLDOMElement ** ppSSTNode);
  42. HRESULT HrCreateActionNode(IN HINF hinf,
  43. IN LPTSTR szActionLine,
  44. IN IXMLDOMDocument * pScpdDoc,
  45. OUT IXMLDOMElement ** ppActionNode);
  46. HRESULT HrCreateActionListNode(IN HINF hinf,
  47. IN IXMLDOMDocument * pScpdDoc,
  48. OUT IXMLDOMElement ** ppActionListNode);
  49. BOOL IsStandardOperation(TCHAR * szOpName, DWORD * pnArgs, DWORD * pnConsts);
  50. //
  51. // Create scpd doc for service from the config file and save to
  52. // specified destination
  53. //
  54. EXTERN_C
  55. VOID
  56. __cdecl
  57. wmain (
  58. IN INT argc,
  59. IN PCWSTR argv[])
  60. {
  61. HRESULT hr = S_OK;
  62. if (argc != 3)
  63. {
  64. _tprintf(TEXT("\nUsage: \n %s\n\n"),
  65. TEXT("<Service INF file>, <SCPD xml file name and path>"));
  66. return;
  67. };
  68. TCHAR szSvcConfigFile[MAX_PATH];
  69. WszToTszBuf(szSvcConfigFile, argv[1], MAX_PATH);
  70. LPCWSTR pszScpdFileWithPath = argv[2];
  71. hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
  72. if (FAILED(hr))
  73. {
  74. TraceError("CoInitializeEx", hr);
  75. return;
  76. }
  77. IXMLDOMDocument *pScpdDoc = NULL;
  78. // Create a new document object
  79. hr = CoCreateInstance(CLSID_DOMDocument30,
  80. NULL,
  81. CLSCTX_INPROC_SERVER,
  82. IID_IXMLDOMDocument,
  83. (void **) &pScpdDoc);
  84. if (SUCCEEDED(hr))
  85. {
  86. hr = pScpdDoc->put_preserveWhiteSpace(VARIANT_TRUE);
  87. if (S_OK == hr)
  88. {
  89. // Build <?xml version="1.0"?>
  90. IXMLDOMProcessingInstruction * piVersion = NULL;
  91. BSTR bstrTarget = SysAllocString(L"xml");
  92. if (bstrTarget)
  93. {
  94. BSTR bstrData = SysAllocString(L"version=\"1.0\"");
  95. if (bstrData)
  96. {
  97. hr = pScpdDoc->createProcessingInstruction(
  98. bstrTarget, bstrData, &piVersion);
  99. if (SUCCEEDED(hr))
  100. {
  101. // Append the <version> element to the document.
  102. hr = pScpdDoc->appendChild(piVersion, NULL);
  103. piVersion->Release();
  104. if (FAILED(hr))
  105. {
  106. TraceError("Failed to append <version> to document.", hr);
  107. }
  108. SysFreeString(bstrTarget);
  109. SysFreeString(bstrData);
  110. }
  111. }
  112. else
  113. {
  114. hr = E_OUTOFMEMORY;
  115. }
  116. }
  117. else
  118. {
  119. hr = E_OUTOFMEMORY;
  120. }
  121. // Build <scpd> element
  122. VARIANT vNULL;
  123. vNULL.vt = VT_EMPTY;
  124. IXMLDOMElement * pScpdNode = NULL;
  125. hr = HrCreateScpdNode(pScpdDoc, &pScpdNode);
  126. if (SUCCEEDED(hr))
  127. {
  128. // open the config file
  129. HINF hinf = NULL;
  130. UINT unErrorLine;
  131. hr = HrSetupOpenConfigFile(szSvcConfigFile, &unErrorLine, &hinf);
  132. if (S_OK == hr)
  133. {
  134. Assert(IsValidHandle(hinf));
  135. // Build <serviceStateTable> element
  136. IXMLDOMElement * pSSTNode = NULL;
  137. hr = HrCreateServiceStateTableNode(hinf, pScpdDoc, &pSSTNode);
  138. if (SUCCEEDED(hr))
  139. {
  140. Assert(pSSTNode);
  141. hr = pScpdNode->insertBefore(pSSTNode,
  142. vNULL,
  143. NULL);
  144. pSSTNode->Release();
  145. if (FAILED(hr))
  146. {
  147. TraceError("Failed to insert <serviceStateTable> element", hr);
  148. }
  149. else
  150. {
  151. // Build <actionList> element
  152. IXMLDOMElement * pActionListNode = NULL;
  153. hr = HrCreateActionListNode(hinf, pScpdDoc, &pActionListNode);
  154. if (SUCCEEDED(hr))
  155. {
  156. Assert(pActionListNode);
  157. hr = pScpdNode->insertBefore(pActionListNode,
  158. vNULL,
  159. NULL);
  160. pActionListNode->Release();
  161. if (FAILED(hr))
  162. {
  163. TraceError("Failed to insert <actionList> element", hr);
  164. }
  165. }
  166. }
  167. }
  168. SetupCloseInfFileSafe(hinf);
  169. }
  170. else
  171. {
  172. TraceTag(ttidUpdiag, "Failed to open file %s, line = %d",
  173. szSvcConfigFile, unErrorLine);
  174. }
  175. // Append the <scpd> element to the document.
  176. if (SUCCEEDED(hr))
  177. {
  178. hr = pScpdDoc->appendChild(pScpdNode, NULL);
  179. pScpdNode->Release();
  180. if (FAILED(hr))
  181. {
  182. TraceError("Failed to append <scpd> element to document.", hr);
  183. }
  184. }
  185. }
  186. else
  187. {
  188. TraceError("Failed to create <scpd> element", hr);
  189. }
  190. if (SUCCEEDED(hr))
  191. {
  192. // Persist the xml document
  193. VARIANT vFileName;
  194. vFileName.vt = VT_BSTR;
  195. V_BSTR(&vFileName) = SysAllocString(pszScpdFileWithPath);
  196. hr = pScpdDoc->save(vFileName);
  197. VariantClear(&vFileName);
  198. }
  199. pScpdDoc->Release();
  200. }
  201. }
  202. else
  203. {
  204. TraceError("Failed to create XML DOM Document object", hr);
  205. }
  206. CoUninitialize();
  207. }
  208. //
  209. // Create the <scpd> note that will include a serviceStateTable and
  210. // an actionList
  211. //
  212. HRESULT HrCreateScpdNode(IN IXMLDOMDocument * pScpdDoc,
  213. OUT IXMLDOMElement ** ppScpdNode)
  214. {
  215. HRESULT hr = S_OK;
  216. Assert(ppScpdNode);
  217. *ppScpdNode = NULL;
  218. IXMLDOMElement * pScpdNode = NULL;
  219. BSTR bstrElementName = SysAllocString(L"scpd");
  220. if (bstrElementName)
  221. {
  222. hr = pScpdDoc->createElement(bstrElementName, &pScpdNode);
  223. if (SUCCEEDED(hr))
  224. {
  225. // set the xmlns attribute
  226. BSTR bstrAttrName = SysAllocString(L"xmlns");
  227. if (bstrAttrName)
  228. {
  229. VARIANT vValue;
  230. vValue.vt = VT_BSTR;
  231. V_BSTR(&vValue) = SysAllocString(L"x-schema:scpdl-schema.xml");
  232. hr = pScpdNode->setAttribute(bstrAttrName, vValue);
  233. SysFreeString(bstrAttrName);
  234. VariantClear(&vValue);
  235. }
  236. else
  237. {
  238. hr = E_OUTOFMEMORY;
  239. }
  240. if (SUCCEEDED(hr))
  241. {
  242. *ppScpdNode = pScpdNode;
  243. pScpdNode->AddRef();
  244. }
  245. else
  246. {
  247. TraceError("HrCreateScpdNode: Failed to set xmlns attribute", hr);
  248. }
  249. pScpdNode->Release();
  250. }
  251. else
  252. {
  253. TraceError("HrCreateScpdNode: Failed to create <scpd> element", hr);
  254. }
  255. SysFreeString(bstrElementName);
  256. }
  257. else
  258. {
  259. hr = E_OUTOFMEMORY;
  260. TraceError("HrCreateScpdNode: Failed to allocate BSTR for element name", hr);
  261. }
  262. TraceError("HrCreateScpdNode", hr);
  263. return hr;
  264. }
  265. HRESULT HrCreateServiceStateTableNode(IN HINF hinf,
  266. IN IXMLDOMDocument * pScpdDoc,
  267. OUT IXMLDOMElement ** ppSSTNode)
  268. {
  269. HRESULT hr = S_OK;
  270. Assert(ppSSTNode);
  271. *ppSSTNode = NULL;
  272. IXMLDOMElement * pSSTNode = NULL;
  273. BSTR bstrElementName = SysAllocString(L"serviceStateTable");
  274. if (bstrElementName)
  275. {
  276. hr = pScpdDoc->createElement(bstrElementName, &pSSTNode);
  277. if (SUCCEEDED(hr))
  278. {
  279. // get the [StateTable] section
  280. INFCONTEXT ctx;
  281. hr = HrSetupFindFirstLine(hinf, TEXT("StateTable"), NULL, &ctx);
  282. if (S_OK == hr)
  283. {
  284. // loop through [StateTable] section and create stateVariable's
  285. TCHAR szKey[LINE_LEN]; // LINE_LEN defined in setupapi.h as 256
  286. TCHAR szVariableLine[LINE_LEN];
  287. IXMLDOMElement * pVariableNode = NULL;
  288. VARIANT vNULL;
  289. vNULL.vt = VT_EMPTY;
  290. do
  291. {
  292. // Retrieve a line from the ActionSet section
  293. hr = HrSetupGetStringField(ctx,0,szKey,celems(szKey),NULL);
  294. if(S_OK == hr)
  295. {
  296. // varify this is a "Variable"
  297. szKey[celems(szKey)-1] = L'\0';
  298. if (lstrcmpi(szKey, TEXT("Variable")))
  299. {
  300. TraceTag(ttidUpdiag, "Wrong key in the StateTable section: %s", szKey);
  301. continue;
  302. }
  303. // get the line text
  304. hr = HrSetupGetLineText(ctx, szVariableLine, celems(szVariableLine),
  305. NULL);
  306. if (S_OK == hr)
  307. {
  308. // Add variable in this line
  309. hr = HrCreateStateVariableNode(szVariableLine, pScpdDoc, &pVariableNode);
  310. if (SUCCEEDED(hr))
  311. {
  312. Assert(pVariableNode);
  313. hr = pSSTNode->insertBefore(pVariableNode,
  314. vNULL,
  315. NULL);
  316. pVariableNode->Release();
  317. }
  318. }
  319. }
  320. }
  321. while (S_OK == (hr = HrSetupFindNextLine(ctx, &ctx)));
  322. if (hr == S_FALSE)
  323. {
  324. // S_FALSE will terminate the loop successfully, so convert it to S_OK
  325. // here.
  326. hr = S_OK;
  327. }
  328. if (S_OK == hr)
  329. {
  330. *ppSSTNode = pSSTNode;
  331. pSSTNode->AddRef();
  332. }
  333. }
  334. else
  335. {
  336. TraceError("HrCreateScpdNode: [StateTable] section not found in inf", hr);
  337. }
  338. }
  339. else
  340. {
  341. TraceError("HrCreateScpdNode: Failed to create <serviceStateTable> element", hr);
  342. }
  343. SysFreeString(bstrElementName);
  344. }
  345. else
  346. {
  347. hr = E_OUTOFMEMORY;
  348. TraceError("HrCreateServiceStateTableNode: Failed to allocate BSTR for element name", hr);
  349. }
  350. TraceError("HrCreateServiceStateTableNode", hr);
  351. return hr;
  352. }
  353. HRESULT HrAddElementWithText(IXMLDOMDocument * pDoc,
  354. IXMLDOMElement * pParentNode,
  355. LPTSTR szElementName,
  356. LPTSTR szElementText)
  357. {
  358. HRESULT hr = S_OK;
  359. IXMLDOMElement * pNewNode = NULL;
  360. VARIANT vNull;
  361. vNull.vt = VT_EMPTY;
  362. BSTR bstrElementName = NULL;
  363. BSTR bstrTextValue = NULL;
  364. WCHAR * wszElementName = WszFromTsz(szElementName);
  365. WCHAR * wszElementText = WszFromTsz(szElementText);
  366. if (!wszElementName || !wszElementText)
  367. {
  368. hr = E_OUTOFMEMORY;
  369. }
  370. else
  371. {
  372. bstrElementName = SysAllocString(wszElementName);
  373. bstrTextValue = SysAllocString(wszElementText);
  374. if (!bstrElementName || !bstrTextValue)
  375. {
  376. hr = E_OUTOFMEMORY;
  377. }
  378. delete wszElementName;
  379. delete wszElementText;
  380. }
  381. if (SUCCEEDED(hr))
  382. {
  383. hr = pDoc->createElement(bstrElementName, &pNewNode);
  384. if (SUCCEEDED(hr))
  385. {
  386. IXMLDOMText * pText = NULL;
  387. hr = pDoc->createTextNode(bstrTextValue, &pText);
  388. if (SUCCEEDED(hr))
  389. {
  390. hr = pNewNode->insertBefore(pText, vNull, NULL);
  391. if (FAILED(hr))
  392. {
  393. TraceError("HrAddElementWithText: Failed to insert text node", hr);
  394. }
  395. pText->Release();
  396. }
  397. else
  398. {
  399. TraceError("HrAddElementWithText: Failed to create text node", hr);
  400. }
  401. if (SUCCEEDED(hr))
  402. {
  403. hr = pParentNode->insertBefore(pNewNode, vNull, NULL);
  404. if (FAILED(hr))
  405. {
  406. TraceError("HrAddElementWithText: Failed to insert new node", hr);
  407. }
  408. }
  409. pNewNode->Release();
  410. }
  411. else
  412. {
  413. TraceError("HrAddElementWithText: Could not create new element", hr);
  414. }
  415. SysFreeString(bstrElementName);
  416. SysFreeString(bstrTextValue);
  417. }
  418. TraceError("HrAddElementWithText", hr);
  419. return hr;
  420. }
  421. BOOL fIsValidDataType(LPTSTR szBuf)
  422. {
  423. return ((lstrcmpi(szBuf, TEXT("number")) ==0) ||
  424. (lstrcmpi(szBuf, TEXT("string")) ==0) ||
  425. (lstrcmpi(szBuf, TEXT("dateTime")) ==0) ||
  426. (lstrcmpi(szBuf, TEXT("boolean")) ==0) ||
  427. (lstrcmpi(szBuf, TEXT("ByteBlock")) ==0));
  428. }
  429. HRESULT HrAddAllowedValueNode( IXMLDOMDocument * pDoc,
  430. IXMLDOMElement * pVariableNode,
  431. LPTSTR szBuf)
  432. {
  433. HRESULT hr = S_OK;
  434. Assert(*szBuf == '(');
  435. szBuf++;
  436. IXMLDOMElement * pAllowedValueNode = NULL;
  437. BSTR bstrElementName;
  438. // we assume that ".." specifies a range, otherwise it's a comma separated
  439. // list of allowed values
  440. TCHAR * pChar = _tcsstr(szBuf, TEXT(".."));
  441. if (pChar)
  442. {
  443. // we have a range
  444. // BUGBUG: we should check if data type of the min, max & step
  445. // matches the variable type
  446. TCHAR * szMin, * szMax, * szStep;
  447. szMin = szBuf;
  448. *pChar = '\0';
  449. szMax = pChar+2;
  450. pChar = _tcschr(szMax, TEXT(','));
  451. if (pChar)
  452. {
  453. *pChar = '\0';
  454. szStep = ++pChar;
  455. pChar = _tcschr(szStep, TEXT(')'));
  456. if (pChar)
  457. {
  458. *pChar = '\0';
  459. bstrElementName = SysAllocString(L"allowedValueRange");
  460. if (bstrElementName)
  461. {
  462. hr = pDoc->createElement(bstrElementName, &pAllowedValueNode);
  463. if (SUCCEEDED(hr))
  464. {
  465. hr = HrAddElementWithText(pDoc, pAllowedValueNode, TEXT("minimum"), szMin);
  466. if (SUCCEEDED(hr))
  467. {
  468. hr = HrAddElementWithText(pDoc, pAllowedValueNode, TEXT("maximum"), szMax);
  469. if (SUCCEEDED(hr))
  470. {
  471. hr = HrAddElementWithText(pDoc, pAllowedValueNode, TEXT("step"), szStep);
  472. }
  473. }
  474. }
  475. SysFreeString(bstrElementName);
  476. }
  477. else
  478. {
  479. hr = E_OUTOFMEMORY;
  480. }
  481. }
  482. else
  483. {
  484. TraceTag(ttidUpdiag, "HrAddAllowedValueNode: missing closing )");
  485. hr = E_INVALIDARG;
  486. }
  487. }
  488. else
  489. {
  490. TraceTag(ttidUpdiag, "HrAddAllowedValueNode: step not specified");
  491. hr = E_INVALIDARG;
  492. }
  493. }
  494. else
  495. {
  496. // we have a list of allowed values
  497. pChar = _tcschr(szBuf, TEXT(')'));
  498. if (pChar)
  499. {
  500. *pChar = '\0';
  501. if (lstrlen(szBuf))
  502. {
  503. bstrElementName = SysAllocString(L"allowedValueList");
  504. if (bstrElementName)
  505. {
  506. hr = pDoc->createElement(bstrElementName, &pAllowedValueNode);
  507. if (SUCCEEDED(hr))
  508. {
  509. while ((S_OK ==hr) && (pChar = _tcschr(szBuf, TEXT(','))))
  510. {
  511. *pChar = '\0';
  512. hr = HrAddElementWithText(pDoc, pAllowedValueNode,
  513. TEXT("allowedValue"), szBuf);
  514. szBuf = ++pChar;
  515. }
  516. // add the last one
  517. if (*szBuf)
  518. {
  519. hr = HrAddElementWithText(pDoc, pAllowedValueNode,
  520. TEXT("allowedValue"), szBuf);
  521. }
  522. else
  523. {
  524. TraceTag(ttidUpdiag, "HrAddAllowedValueNode: invalid syntax");
  525. hr = E_INVALIDARG;
  526. }
  527. }
  528. SysFreeString(bstrElementName);
  529. }
  530. else
  531. {
  532. hr = E_OUTOFMEMORY;
  533. }
  534. }
  535. }
  536. else
  537. {
  538. TraceTag(ttidUpdiag, "HrAddAllowedValueNode: missing closing )");
  539. hr = E_INVALIDARG;
  540. }
  541. }
  542. if (pAllowedValueNode && (S_OK == hr))
  543. {
  544. // append the allowed value node to "stateVariable"
  545. VARIANT vNull;
  546. vNull.vt = VT_EMPTY;
  547. hr = pVariableNode->insertBefore(pAllowedValueNode, vNull, NULL);
  548. }
  549. TraceError("HrAddAllowedValueRangeNode" , hr);
  550. return hr;
  551. }
  552. HRESULT HrCreateStateVariableNode(IN LPTSTR szVariableLine,
  553. IN IXMLDOMDocument * pScpdDoc,
  554. OUT IXMLDOMElement ** ppVariableNode)
  555. {
  556. HRESULT hr = S_OK;
  557. Assert(ppVariableNode);
  558. *ppVariableNode = NULL;
  559. IXMLDOMElement * pVariableNode = NULL;
  560. BSTR bstrElementName = SysAllocString(L"stateVariable");
  561. if (bstrElementName)
  562. {
  563. hr = pScpdDoc->createElement(bstrElementName, &pVariableNode);
  564. if (SUCCEEDED(hr))
  565. {
  566. TCHAR szBuf[MAX_PATH];
  567. if (fGetNextField(&szVariableLine, szBuf))
  568. {
  569. hr = HrAddElementWithText(pScpdDoc, pVariableNode, TEXT("name"), szBuf);
  570. if (SUCCEEDED(hr))
  571. {
  572. if (fGetNextField(&szVariableLine, szBuf))
  573. {
  574. if (fIsValidDataType(szBuf))
  575. {
  576. hr = HrAddElementWithText(pScpdDoc, pVariableNode,
  577. TEXT("dataType"), szBuf);
  578. // AllowedValueRange is optional
  579. if (SUCCEEDED(hr) && fGetNextField(&szVariableLine, szBuf))
  580. {
  581. hr = HrAddAllowedValueNode(pScpdDoc, pVariableNode, szBuf);
  582. }
  583. if (SUCCEEDED(hr) && fGetNextField(&szVariableLine, szBuf))
  584. {
  585. hr = HrAddElementWithText(pScpdDoc, pVariableNode,
  586. TEXT("defaultValue"), szBuf);
  587. }
  588. }
  589. else
  590. {
  591. hr = E_INVALIDARG;
  592. TraceError("HrCreateStateVariableNode: invalid data type specified", hr);
  593. }
  594. }
  595. else
  596. {
  597. hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  598. }
  599. }
  600. }
  601. else
  602. {
  603. hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  604. }
  605. if (S_OK == hr)
  606. {
  607. *ppVariableNode = pVariableNode;
  608. pVariableNode->AddRef();
  609. }
  610. }
  611. else
  612. {
  613. TraceError("HrCreateStateVariableNode: Failed to create <stateVariable> element", hr);
  614. }
  615. SysFreeString(bstrElementName);
  616. }
  617. else
  618. {
  619. hr = E_OUTOFMEMORY;
  620. TraceError("HrCreateStateVariableNode: Failed to allocate BSTR for element name", hr);
  621. }
  622. TraceError("HrCreateStateVariableNode", hr);
  623. return hr;
  624. }
  625. HRESULT HrCreateActionListNode(IN HINF hinf,
  626. IN IXMLDOMDocument * pScpdDoc,
  627. OUT IXMLDOMElement ** ppActionListNode)
  628. {
  629. HRESULT hr = S_OK;
  630. Assert(ppActionListNode);
  631. *ppActionListNode = NULL;
  632. IXMLDOMElement * pActionListNode = NULL;
  633. BSTR bstrElementName = SysAllocString(L"actionList");
  634. if (bstrElementName)
  635. {
  636. hr = pScpdDoc->createElement(bstrElementName, &pActionListNode);
  637. if (SUCCEEDED(hr))
  638. {
  639. // get the [ActionSet] section
  640. INFCONTEXT ctx;
  641. hr = HrSetupFindFirstLine(hinf, TEXT("ActionSet"), NULL, &ctx);
  642. if (S_OK == hr)
  643. {
  644. // loop through [ActionSet] section and create actions
  645. TCHAR szKey[LINE_LEN]; // LINE_LEN defined in setupapi.h as 256
  646. TCHAR szActionLine[LINE_LEN];
  647. IXMLDOMElement * pActionNode = NULL;
  648. VARIANT vNULL;
  649. vNULL.vt = VT_EMPTY;
  650. do
  651. {
  652. // Retrieve a line from the ActionSet section
  653. hr = HrSetupGetStringField(ctx,0,szKey,celems(szKey),NULL);
  654. if(S_OK == hr)
  655. {
  656. // varify this is a "Action"
  657. szKey[celems(szKey)-1] = L'\0';
  658. if (lstrcmpi(szKey, TEXT("Action")))
  659. {
  660. TraceTag(ttidUpdiag, "Wrong key in the ActionSet section: %s", szKey);
  661. continue;
  662. }
  663. // get the line text
  664. hr = HrSetupGetLineText(ctx, szActionLine, celems(szActionLine),
  665. NULL);
  666. if (S_OK == hr)
  667. {
  668. // Add action in this line
  669. hr = HrCreateActionNode(hinf, szActionLine, pScpdDoc, &pActionNode);
  670. if (SUCCEEDED(hr))
  671. {
  672. Assert(pActionNode);
  673. hr = pActionListNode->insertBefore( pActionNode,
  674. vNULL,
  675. NULL);
  676. pActionNode->Release();
  677. }
  678. }
  679. }
  680. }
  681. while (S_OK == (hr = HrSetupFindNextLine(ctx, &ctx)));
  682. if (hr == S_FALSE)
  683. {
  684. // S_FALSE will terminate the loop successfully, so convert it to S_OK
  685. // here.
  686. hr = S_OK;
  687. }
  688. if (S_OK == hr)
  689. {
  690. *ppActionListNode = pActionListNode;
  691. pActionListNode->AddRef();
  692. }
  693. }
  694. else
  695. {
  696. TraceError("HrCreateScpdNode: [ActionSet] not found in service inf", hr);
  697. }
  698. }
  699. else
  700. {
  701. TraceError("HrCreateScpdNode: Failed to create <actionList> element", hr);
  702. }
  703. SysFreeString(bstrElementName);
  704. }
  705. else
  706. {
  707. hr = E_OUTOFMEMORY;
  708. TraceError("HrCreateScpdNode: Failed to allocate BSTR for element name", hr);
  709. }
  710. TraceError("HrCreateActionListNode", hr);
  711. return hr;
  712. }
  713. //
  714. // Construct the list of arguments and related state variable
  715. // for each argument
  716. //
  717. HRESULT HrGetArgumentList(IN HINF hinf,
  718. IN LPTSTR szActionName,
  719. IN LPTSTR szActionArgList,
  720. OUT ARG_LIST * pargList)
  721. {
  722. HRESULT hr = S_OK;
  723. BOOL fNamedArgs = FALSE;
  724. if (szActionArgList)
  725. {
  726. fNamedArgs = !!lstrlen(szActionArgList);
  727. }
  728. DWORD dwNum = 1;
  729. // Loop over the list of operations for this action
  730. INFCONTEXT ctx;
  731. hr = HrSetupFindFirstLine(hinf, szActionName, NULL, &ctx);
  732. if (S_OK == hr)
  733. {
  734. do
  735. {
  736. TCHAR szKey[LINE_LEN]; // LINE_LEN defined in setupapi.h as 256
  737. TCHAR szOpLine[LINE_LEN];
  738. // Retrieve a line from the Action
  739. hr = HrSetupGetStringField(ctx, 0, szKey, celems(szKey), NULL);
  740. if(S_OK == hr)
  741. {
  742. // varify this is an "Operation"
  743. szKey[celems(szKey)-1] = L'\0';
  744. if (lstrcmpi(szKey, TEXT("Operation")))
  745. {
  746. TraceTag(ttidUpdiag, "ERROR! HrGetRelatedVariableList: Wrong key in the Operation section: %s", szKey);
  747. continue;
  748. }
  749. hr = HrSetupGetLineText(ctx, szOpLine, celems(szOpLine), NULL);
  750. if (S_OK == hr)
  751. {
  752. // Get the affected variables in this operation
  753. TCHAR * szRelatedVariable;
  754. TCHAR * pChar = _tcschr(szOpLine, TEXT('('));
  755. if (pChar)
  756. {
  757. *pChar ='\0';
  758. TCHAR * szOpName = szOpLine;
  759. pChar ++;
  760. szRelatedVariable = pChar;
  761. DWORD nArgs;
  762. DWORD nConsts;
  763. if (IsStandardOperation(szOpName, &nArgs, &nConsts))
  764. {
  765. // get the Variable name
  766. if (nArgs+nConsts ==0)
  767. {
  768. pChar = _tcschr(szRelatedVariable, TEXT(')'));
  769. }
  770. else
  771. {
  772. pChar = _tcschr(szRelatedVariable, TEXT(','));
  773. }
  774. if (pChar)
  775. {
  776. *pChar = TEXT('\0');
  777. // BUGBUG: Can we check if the variable is valid ??
  778. for (DWORD iArg =0; iArg < nArgs; iArg++)
  779. {
  780. TCHAR szArgName[256];
  781. *szArgName = '\0';
  782. if (!fNamedArgs)
  783. {
  784. // generate argument name, add to the list
  785. lstrcpy(szArgName, TEXT("Argument_"));
  786. TCHAR szNum[2];
  787. _itot(dwNum, szNum, 10);
  788. lstrcat(szArgName, szNum);
  789. dwNum++;
  790. }
  791. else
  792. {
  793. // use the argument name specified in the inf
  794. pChar = _tcschr(szActionArgList, TEXT(','));
  795. if (pChar)
  796. {
  797. *pChar = '\0';
  798. lstrcpy(szArgName, szActionArgList);
  799. pChar ++;
  800. szActionArgList = pChar;
  801. }
  802. else
  803. {
  804. lstrcpy(szArgName, szActionArgList);
  805. }
  806. }
  807. if (!(*szArgName))
  808. {
  809. TraceTag(ttidUpdiag, "Argument list incomplete!");
  810. hr = E_INVALIDARG;
  811. break;
  812. }
  813. else
  814. {
  815. if (pargList->cArgs < MAX_ACTION_ARGUMENTS)
  816. {
  817. TraceTag(ttidUpdiag, "HrGetArgumentList: action: %s, argument: %s, relatedStateVariable: %s",
  818. szActionName, szArgName, szRelatedVariable);
  819. lstrcpy(pargList->rgArguments[pargList->cArgs].szArg, szArgName);
  820. lstrcpy(pargList->rgArguments[pargList->cArgs].szVariable, szRelatedVariable);
  821. pargList->cArgs++;
  822. }
  823. else
  824. {
  825. TraceTag(ttidUpdiag, "Too many arguments!");
  826. hr = E_INVALIDARG;
  827. break;
  828. }
  829. }
  830. }
  831. }
  832. }
  833. else
  834. {
  835. TraceTag(ttidUpdiag, "ERROR! HrGetArgumentList: unknown operation: %s",
  836. szOpName);
  837. }
  838. }
  839. }
  840. }
  841. }
  842. while (S_OK == (hr = HrSetupFindNextLine(ctx, &ctx)));
  843. }
  844. if (hr == S_FALSE)
  845. {
  846. // S_FALSE will terminate the loop successfully, so convert it to S_OK
  847. // here.
  848. hr = S_OK;
  849. }
  850. TraceError("HrGetArgumentList",hr);
  851. return hr;
  852. }
  853. HRESULT HrAddArgumentNode( IXMLDOMDocument * pDoc,
  854. IXMLDOMElement * pArgumentListNode,
  855. LPTSTR szArgumentName,
  856. LPTSTR szVariableName)
  857. {
  858. HRESULT hr = S_OK;
  859. IXMLDOMElement * pArgumentNode = NULL;
  860. BSTR bstrElementName = SysAllocString(L"argument");
  861. if (bstrElementName)
  862. {
  863. hr = pDoc->createElement(bstrElementName, &pArgumentNode);
  864. if (SUCCEEDED(hr))
  865. {
  866. // name
  867. hr = HrAddElementWithText(pDoc, pArgumentNode,
  868. TEXT("name"), szArgumentName);
  869. if (SUCCEEDED(hr))
  870. {
  871. // relatedStateVariable
  872. hr = HrAddElementWithText(pDoc, pArgumentNode,
  873. TEXT("relatedStateVariable"), szVariableName);
  874. }
  875. }
  876. else
  877. {
  878. TraceTag(ttidUpdiag, "HrAddArgumentNode: failed creating <argument> node");
  879. }
  880. SysFreeString(bstrElementName);
  881. }
  882. else
  883. {
  884. hr = E_OUTOFMEMORY;
  885. }
  886. if (pArgumentNode && (S_OK == hr))
  887. {
  888. // append the argument node to "argumentList"
  889. VARIANT vNull;
  890. vNull.vt = VT_EMPTY;
  891. hr = pArgumentListNode->insertBefore(pArgumentNode, vNull, NULL);
  892. pArgumentNode->Release();
  893. }
  894. TraceError("HrAddArgumentNode", hr);
  895. return hr;
  896. }
  897. HRESULT HrCreateActionNode(IN HINF hinf,
  898. IN LPTSTR szActionLine,
  899. IN IXMLDOMDocument * pDoc,
  900. OUT IXMLDOMElement ** ppActionNode)
  901. {
  902. HRESULT hr = S_OK;
  903. Assert(ppActionNode);
  904. *ppActionNode = NULL;
  905. IXMLDOMElement * pActionNode = NULL;
  906. BSTR bstrAction = SysAllocString(L"action");
  907. if (bstrAction)
  908. {
  909. hr = pDoc->createElement(bstrAction, &pActionNode);
  910. if (SUCCEEDED(hr))
  911. {
  912. TCHAR * szActionName = szActionLine;
  913. TCHAR * szActionArgList = NULL;
  914. TCHAR * pChar = _tcschr(szActionLine, TEXT('('));
  915. if (pChar)
  916. {
  917. *pChar = '\0';
  918. pChar ++;
  919. szActionArgList = pChar;
  920. pChar = _tcschr(szActionArgList, TEXT(')'));
  921. if (pChar)
  922. {
  923. *pChar = '\0';
  924. }
  925. else
  926. {
  927. TraceTag(ttidUpdiag, "HrCreateActionNode: argument list missing closing )");
  928. hr = E_INVALIDARG;
  929. }
  930. }
  931. if (SUCCEEDED(hr))
  932. {
  933. // <name>
  934. hr = HrAddElementWithText(pDoc, pActionNode, TEXT("name"), szActionName);
  935. if (SUCCEEDED(hr))
  936. {
  937. // <argumentList>
  938. ARG_LIST argList;
  939. argList.cArgs = 0;
  940. hr = HrGetArgumentList(hinf, szActionName, szActionArgList, &argList);
  941. if (SUCCEEDED(hr) && (argList.cArgs > 0))
  942. {
  943. IXMLDOMElement * pArgumentListNode = NULL;
  944. BSTR bstrArgumentList = SysAllocString(L"argumentList");
  945. if (bstrArgumentList)
  946. {
  947. hr = pDoc->createElement(bstrArgumentList, &pArgumentListNode);
  948. if (SUCCEEDED(hr))
  949. {
  950. for (DWORD iArg = 0; iArg < argList.cArgs; iArg++)
  951. {
  952. hr = HrAddArgumentNode(pDoc, pArgumentListNode,
  953. argList.rgArguments[iArg].szArg,
  954. argList.rgArguments[iArg].szVariable);
  955. if (FAILED(hr))
  956. break;
  957. }
  958. if (SUCCEEDED(hr))
  959. {
  960. // append the argumentList node to "action"
  961. VARIANT vNull;
  962. vNull.vt = VT_EMPTY;
  963. hr = pActionNode->insertBefore(pArgumentListNode, vNull, NULL);
  964. pArgumentListNode->Release();
  965. }
  966. }
  967. else
  968. {
  969. TraceTag(ttidUpdiag, "HrCreateActionNode: failed creating argument list node");
  970. }
  971. SysFreeString(bstrArgumentList);
  972. }
  973. else
  974. {
  975. hr = E_OUTOFMEMORY;
  976. }
  977. }
  978. }
  979. }
  980. }
  981. else
  982. {
  983. TraceTag(ttidUpdiag, "HrCreateActionNode: Failed to create <action> node.");
  984. }
  985. SysFreeString(bstrAction);
  986. }
  987. else
  988. {
  989. hr = E_OUTOFMEMORY;
  990. }
  991. if (S_OK == hr)
  992. {
  993. *ppActionNode = pActionNode;
  994. pActionNode->AddRef();
  995. }
  996. TraceError("HrCreateActionNode", hr);
  997. return hr;
  998. }