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.

3091 lines
94 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 2000.
  5. //
  6. // File: A U T O M A T I O N P R O X Y . C P P
  7. //
  8. // Contents: Implementation of the Automation Proxy class
  9. //
  10. // Notes:
  11. //
  12. // Author: spather 2000/09/25
  13. //
  14. //----------------------------------------------------------------------------
  15. #include <pch.h>
  16. #pragma hdrstop
  17. #include <msxml2.h>
  18. #include "uhbase.h"
  19. #include "AutomationProxy.h"
  20. #include "ncstring.h"
  21. #include "ncxml.h"
  22. #include "ComUtility.h"
  23. #include "uhcommon.h"
  24. CUPnPAutomationProxy::CUPnPAutomationProxy()
  25. {
  26. m_fInitialized = FALSE;
  27. m_pdispService = NULL;
  28. m_cVariables = 0;
  29. m_cEventedVariables = 0;
  30. m_rgVariables = NULL;
  31. m_cActions = 0;
  32. m_rgActions = NULL;
  33. m_wszServiceType = NULL;
  34. }
  35. CUPnPAutomationProxy::~CUPnPAutomationProxy()
  36. {
  37. if (m_pdispService)
  38. {
  39. m_pdispService->Release();
  40. }
  41. FreeVariableTable();
  42. FreeActionTable();
  43. if (m_wszServiceType)
  44. {
  45. delete[] m_wszServiceType;
  46. }
  47. m_fInitialized = FALSE;
  48. }
  49. // ATL methods
  50. HRESULT
  51. CUPnPAutomationProxy::FinalConstruct()
  52. {
  53. return S_OK;
  54. }
  55. HRESULT
  56. CUPnPAutomationProxy::FinalRelease()
  57. {
  58. return S_OK;
  59. }
  60. STDMETHODIMP
  61. CUPnPAutomationProxy::Initialize(
  62. /*[in]*/ IUnknown * punkSvcObject,
  63. /*[in]*/ LPWSTR pszSvcDescription,
  64. /*[in]*/ LPWSTR pszSvcType,
  65. /*[in]*/ BOOL bRunning)
  66. {
  67. HRESULT hr = S_OK;
  68. hr = HrIsAllowedCOMCallLocality((CALL_LOCALITY) CALL_LOCALITY_INPROC );
  69. if (FAILED(hr))
  70. {
  71. TraceError("HrIsAllowedCOMCallLocality failed !",hr);
  72. goto Cleanup;
  73. }
  74. Assert(!m_fInitialized);
  75. Assert(pszSvcType);
  76. if (punkSvcObject)
  77. {
  78. m_wszServiceType = WszDupWsz(pszSvcType);
  79. if (m_wszServiceType)
  80. {
  81. hr = punkSvcObject->QueryInterface(IID_IDispatch,
  82. (void **) &m_pdispService);
  83. if(SUCCEEDED(hr))
  84. {
  85. if(bRunning)
  86. {
  87. hr = HrCopyProxyIdentity(m_pdispService, punkSvcObject);
  88. }
  89. }
  90. if (SUCCEEDED(hr))
  91. {
  92. TraceTag(ttidAutomationProxy,
  93. "CUPnPAutomationProxy::Initialize(): "
  94. "Successfully obtained IDispatch pointer on service");
  95. hr = HrProcessServiceDescription(pszSvcDescription);
  96. }
  97. if (SUCCEEDED(hr))
  98. {
  99. m_fInitialized = TRUE;
  100. }
  101. }
  102. else
  103. {
  104. hr = E_OUTOFMEMORY;
  105. TraceError("CUPnPAutomationProxy::Initialize - Unable to allocate service type!",
  106. hr);
  107. }
  108. }
  109. else
  110. {
  111. hr = E_INVALIDARG;
  112. TraceError("CUPnPAutomationProxy::Initialize - NULL service object!",
  113. hr);
  114. }
  115. Cleanup:
  116. TraceError("CUPnPAutomationProxy::Initialize(): "
  117. "Exiting",
  118. hr);
  119. return hr;
  120. }
  121. STDMETHODIMP
  122. CUPnPAutomationProxy::GetDispIdsOfEventedVariables(
  123. /*[out]*/ DWORD * pcEventedVars,
  124. /*[out]*/ DISPID ** prgdispidEventedVars)
  125. {
  126. HRESULT hr = S_OK;
  127. DISPID * rgdispidEventedVars = NULL;
  128. hr = HrIsAllowedCOMCallLocality((CALL_LOCALITY) CALL_LOCALITY_INPROC );
  129. if (FAILED(hr))
  130. {
  131. TraceError("HrIsAllowedCOMCallLocality failed !",hr);
  132. goto Cleanup;
  133. }
  134. Assert(m_fInitialized);
  135. if (prgdispidEventedVars && (m_cEventedVariables > 0))
  136. {
  137. rgdispidEventedVars = (DISPID *) CoTaskMemAlloc(m_cEventedVariables *
  138. sizeof(DISPID));
  139. if (rgdispidEventedVars)
  140. {
  141. ZeroMemory(rgdispidEventedVars,
  142. m_cEventedVariables * sizeof(DISPID));
  143. for (DWORD i = 0, j = 0; i < m_cVariables; i++)
  144. {
  145. if (FALSE == m_rgVariables[i].fNonEvented)
  146. {
  147. rgdispidEventedVars[j] = m_rgVariables[i].dispid;
  148. j++;
  149. }
  150. }
  151. }
  152. else
  153. {
  154. hr = E_OUTOFMEMORY;
  155. TraceError("CUPnPAutomationProxy::GetDispIdsOfEventedVariables(): "
  156. "Could not allocate array of dispids",
  157. hr);
  158. }
  159. }
  160. if (SUCCEEDED(hr))
  161. {
  162. if (pcEventedVars)
  163. {
  164. *pcEventedVars = m_cEventedVariables;
  165. }
  166. if (prgdispidEventedVars)
  167. {
  168. *prgdispidEventedVars = rgdispidEventedVars;
  169. }
  170. }
  171. Cleanup:
  172. TraceError("CUPnPAutomationProxy::GetDispIdsOfEventedVariables(): "
  173. "Exiting",
  174. hr);
  175. return hr;
  176. }
  177. STDMETHODIMP
  178. CUPnPAutomationProxy::QueryStateVariablesByDispIds(
  179. /*[in]*/ DWORD cDispIds,
  180. /*[in]*/ DISPID * rgDispIds,
  181. /*[out]*/ DWORD * pcVariables,
  182. /*[out]*/ LPWSTR ** prgszVariableNames,
  183. /*[out]*/ VARIANT ** prgvarVariableValues,
  184. /*[out]*/ LPWSTR ** prgszVariableDataTypes)
  185. {
  186. HRESULT hr = S_OK;
  187. DWORD cDispIdsToLookUp;
  188. DISPID * rgDispIdsToLookUp;
  189. LPWSTR * rgszVariableNames = NULL;
  190. VARIANT * rgvarVariableValues = NULL;
  191. LPWSTR * rgszVariableDataTypes = NULL;
  192. DWORD cVariables = 0;
  193. hr = HrIsAllowedCOMCallLocality((CALL_LOCALITY) CALL_LOCALITY_INPROC );
  194. if (FAILED(hr))
  195. {
  196. TraceError("HrIsAllowedCOMCallLocality failed !",hr);
  197. goto Cleanup;
  198. }
  199. Assert(m_fInitialized);
  200. if (0 == cDispIds)
  201. {
  202. // This means return all variables. Make an array of all our dispids.
  203. cDispIdsToLookUp = m_cVariables;
  204. rgDispIdsToLookUp = new DISPID[cDispIdsToLookUp];
  205. if (rgDispIdsToLookUp)
  206. {
  207. for (DWORD i = 0; i < cDispIdsToLookUp; i++)
  208. {
  209. rgDispIdsToLookUp[i] = m_rgVariables[i].dispid;
  210. }
  211. }
  212. else
  213. {
  214. hr = E_OUTOFMEMORY;
  215. TraceError("CUPnPAutomationProxy::"
  216. "QueryStateVariablesByDispIds(): "
  217. "Could not allocate array of dispids",
  218. hr);
  219. }
  220. }
  221. else
  222. {
  223. cDispIdsToLookUp = cDispIds;
  224. rgDispIdsToLookUp = rgDispIds;
  225. }
  226. if (SUCCEEDED(hr))
  227. {
  228. // Allocate output arrays of size cDispIds.
  229. rgszVariableNames = (LPWSTR *)CoTaskMemAlloc(
  230. cDispIdsToLookUp * sizeof(LPWSTR));
  231. rgvarVariableValues = (VARIANT *)CoTaskMemAlloc(
  232. cDispIdsToLookUp * sizeof(VARIANT));
  233. rgszVariableDataTypes = (LPWSTR *)CoTaskMemAlloc(
  234. cDispIdsToLookUp * sizeof(LPWSTR));
  235. // Fill in values.
  236. if (rgszVariableNames && rgvarVariableValues && rgszVariableDataTypes)
  237. {
  238. ZeroMemory(rgszVariableNames, cDispIdsToLookUp * sizeof(LPWSTR));
  239. ZeroMemory(rgvarVariableValues, cDispIdsToLookUp * sizeof(VARIANT));
  240. ZeroMemory(rgszVariableDataTypes, cDispIdsToLookUp * sizeof(LPWSTR));
  241. for (DWORD i = 0; SUCCEEDED(hr) && (i < cDispIdsToLookUp); i++)
  242. {
  243. UPNP_STATE_VARIABLE * pVariable = NULL;
  244. cVariables++;
  245. pVariable = LookupVariableByDispID(rgDispIdsToLookUp[i]);
  246. if (pVariable)
  247. {
  248. rgszVariableNames[i] = COMSzFromWsz(pVariable->bstrName);
  249. rgszVariableDataTypes[i] = COMSzFromWsz(pVariable->bstrDataType);
  250. if (rgszVariableNames[i] && rgszVariableDataTypes[i])
  251. {
  252. UINT uArgErr = 0;
  253. DISPPARAMS dispparamsEmpty = {NULL, NULL, 0, 0};
  254. hr = m_pdispService->Invoke(rgDispIdsToLookUp[i],
  255. IID_NULL,
  256. LOCALE_SYSTEM_DEFAULT,
  257. DISPATCH_PROPERTYGET,
  258. &dispparamsEmpty,
  259. &rgvarVariableValues[i],
  260. NULL,
  261. &uArgErr);
  262. if (SUCCEEDED(hr))
  263. {
  264. TraceTag(ttidAutomationProxy,
  265. "CUPnPAutomationProxy::"
  266. "QueryStateVariablesByDispIds(): "
  267. "Successfully obtained value for "
  268. "dispid %d",
  269. rgDispIdsToLookUp[i]);
  270. }
  271. else
  272. {
  273. TraceError("CUPnPAutomationProxy::"
  274. "QueryStateVariablesByDispIds(): "
  275. "IDispatch::Invoke failed",
  276. hr);
  277. }
  278. }
  279. else
  280. {
  281. hr = E_OUTOFMEMORY;
  282. TraceError("CUPnPAutomationProxy::"
  283. "QueryStateVariablesByDispIds(): "
  284. "Could not allocate name/data type strings",
  285. hr);
  286. }
  287. }
  288. else
  289. {
  290. hr = DISP_E_MEMBERNOTFOUND;
  291. }
  292. }
  293. }
  294. else
  295. {
  296. hr = E_OUTOFMEMORY;
  297. TraceError("CUPnPAutomationProxy::"
  298. "QueryStateVariablesByDispIds(): "
  299. "Could not allocate output arrays",
  300. hr);
  301. }
  302. }
  303. // Copy the output arrays to the out parameters.
  304. if (SUCCEEDED(hr))
  305. {
  306. *pcVariables = cVariables;
  307. *prgszVariableNames = rgszVariableNames;
  308. *prgvarVariableValues = rgvarVariableValues;
  309. *prgszVariableDataTypes = rgszVariableDataTypes;
  310. }
  311. else
  312. {
  313. // Clean up. Assume cVariables accurately describes the number
  314. // of initialized items in the arrays.
  315. if (rgszVariableNames)
  316. {
  317. for (DWORD i = 0; i < cVariables; i++)
  318. {
  319. if (rgszVariableNames[i])
  320. {
  321. CoTaskMemFree(rgszVariableNames[i]);
  322. rgszVariableNames[i] = NULL;
  323. }
  324. }
  325. CoTaskMemFree(rgszVariableNames);
  326. rgszVariableNames = NULL;
  327. }
  328. if (rgvarVariableValues)
  329. {
  330. for (DWORD i = 0; i < cVariables; i++)
  331. {
  332. VariantClear(&rgvarVariableValues[i]);
  333. }
  334. CoTaskMemFree(rgvarVariableValues);
  335. rgvarVariableValues = NULL;
  336. }
  337. if (rgszVariableDataTypes)
  338. {
  339. for (DWORD i = 0; i < cVariables; i++)
  340. {
  341. if (rgszVariableDataTypes[i])
  342. {
  343. CoTaskMemFree(rgszVariableDataTypes[i]);
  344. rgszVariableDataTypes[i] = NULL;
  345. }
  346. }
  347. CoTaskMemFree(rgszVariableDataTypes);
  348. rgszVariableDataTypes = NULL;
  349. }
  350. }
  351. // Clean up custom array of dispIds if we have one.
  352. if (rgDispIdsToLookUp != rgDispIds)
  353. {
  354. delete [] rgDispIdsToLookUp;
  355. rgDispIdsToLookUp = NULL;
  356. cDispIdsToLookUp = 0;
  357. }
  358. Cleanup:
  359. TraceError("CUPnPAutomationProxy::"
  360. "QueryStateVariablesByDispIds(): "
  361. "Exiting",
  362. hr);
  363. return hr;
  364. }
  365. STDMETHODIMP
  366. CUPnPAutomationProxy::ExecuteRequest(
  367. /*[in]*/ UPNP_CONTROL_REQUEST * pucreq,
  368. /*[out]*/ UPNP_CONTROL_RESPONSE * pucresp)
  369. {
  370. HRESULT hr = S_OK;
  371. Assert(m_fInitialized);
  372. if (lstrcmpW(pucreq->bstrActionName, L"QueryStateVariable") == 0)
  373. {
  374. hr = HrQueryStateVariable(pucreq, pucresp);
  375. }
  376. else
  377. {
  378. hr = HrInvokeAction(pucreq, pucresp);
  379. }
  380. TraceError("CUPnPAutomationProxy::ExecuteRequest(): "
  381. "Exiting",
  382. hr);
  383. return hr;
  384. }
  385. STDMETHODIMP
  386. CUPnPAutomationProxy::GetVariableType(
  387. /*[in]*/ LPWSTR pszVarName,
  388. /*[out]*/ BSTR * pbstrType)
  389. {
  390. HRESULT hr = S_OK;
  391. BSTR bstrType = NULL;
  392. UPNP_STATE_VARIABLE * pusv = NULL;
  393. hr = HrIsAllowedCOMCallLocality((CALL_LOCALITY) CALL_LOCALITY_INPROC );
  394. if (FAILED(hr))
  395. {
  396. TraceError("HrIsAllowedCOMCallLocality failed !",hr);
  397. goto Cleanup;
  398. }
  399. Assert(m_fInitialized);
  400. pusv = LookupVariableByName(pszVarName);
  401. if (pusv)
  402. {
  403. Assert(pusv->bstrDataType);
  404. bstrType = SysAllocString(pusv->bstrDataType);
  405. }
  406. else
  407. {
  408. hr = E_INVALIDARG;
  409. }
  410. if (SUCCEEDED(hr))
  411. {
  412. *pbstrType = bstrType;
  413. }
  414. else
  415. {
  416. if (bstrType)
  417. {
  418. SysFreeString(bstrType);
  419. bstrType = NULL;
  420. }
  421. }
  422. Cleanup:
  423. TraceError("CUPnPAutomationProxy::GetVariableType(): "
  424. "Exiting",
  425. hr);
  426. return hr;
  427. }
  428. STDMETHODIMP
  429. CUPnPAutomationProxy::GetServiceType(
  430. /*[out]*/ LPWSTR * pszServiceType)
  431. {
  432. HRESULT hr = S_OK;
  433. hr = HrIsAllowedCOMCallLocality((CALL_LOCALITY) CALL_LOCALITY_INPROC );
  434. if (FAILED(hr))
  435. {
  436. TraceError("HrIsAllowedCOMCallLocality failed !",hr);
  437. goto Cleanup;
  438. }
  439. *pszServiceType = (LPWSTR)CoTaskMemAlloc(CbOfSzAndTerm(m_wszServiceType));
  440. if (*pszServiceType)
  441. {
  442. lstrcpy(*pszServiceType, m_wszServiceType);
  443. }
  444. else
  445. {
  446. hr = E_OUTOFMEMORY;
  447. }
  448. Cleanup:
  449. return hr;
  450. }
  451. STDMETHODIMP
  452. CUPnPAutomationProxy::GetInputArgumentNamesAndTypes(
  453. /*[in]*/ LPWSTR pszActionName,
  454. /*[out]*/ DWORD * pcInArguments,
  455. /*[out]*/ BSTR ** prgbstrNames,
  456. /*[out]*/ BSTR ** prgbstrTypes)
  457. {
  458. HRESULT hr = S_OK;
  459. DWORD cInArguments = 0;
  460. BSTR * rgbstrNames = NULL;
  461. BSTR * rgbstrTypes = NULL;
  462. UPNP_ACTION * pua = NULL;
  463. hr = HrIsAllowedCOMCallLocality((CALL_LOCALITY) CALL_LOCALITY_INPROC );
  464. if (FAILED(hr))
  465. {
  466. TraceError("HrIsAllowedCOMCallLocality failed !",hr);
  467. goto Cleanup;
  468. }
  469. Assert(m_fInitialized);
  470. pua = LookupActionByName(pszActionName);
  471. if (pua)
  472. {
  473. // Allocate arrays for the names and data types.
  474. cInArguments = pua->cInArgs;
  475. if (cInArguments > 0)
  476. {
  477. rgbstrNames = (BSTR *) CoTaskMemAlloc(cInArguments * sizeof(BSTR));
  478. rgbstrTypes = (BSTR *) CoTaskMemAlloc(cInArguments * sizeof(BSTR));
  479. if (rgbstrNames && rgbstrTypes)
  480. {
  481. for (DWORD i = 0; SUCCEEDED(hr) && (i < cInArguments); i++)
  482. {
  483. UPNP_STATE_VARIABLE * pusvRelated = NULL;
  484. rgbstrNames[i] = SysAllocString(pua->rgInArgs[i].bstrName);
  485. pusvRelated = pua->rgInArgs[i].pusvRelated;
  486. Assert(pusvRelated);
  487. rgbstrTypes[i] = SysAllocString(pusvRelated->bstrDataType);
  488. if (rgbstrNames[i] && rgbstrTypes[i])
  489. {
  490. TraceTag(ttidAutomationProxy,
  491. "CUPnPAutomationProxy::"
  492. "GetInputArgumentNamesAndTypes(): "
  493. "Successfully copied input argument %S "
  494. "of type %S",
  495. rgbstrNames[i],
  496. rgbstrTypes[i]);
  497. }
  498. else
  499. {
  500. hr = E_OUTOFMEMORY;
  501. TraceError("CUPnPAutomationProxy::"
  502. "GetInputArgumentNamesAndTypes(): "
  503. "Failed to allocate argument name and/or type",
  504. hr);
  505. }
  506. }
  507. }
  508. else
  509. {
  510. hr = E_OUTOFMEMORY;
  511. TraceError("CUPnPAutomationProxy::"
  512. "GetInputArgumentNamesAndTypes(): "
  513. "Failed to allocate output arrays",
  514. hr);
  515. }
  516. }
  517. }
  518. else
  519. {
  520. hr = E_INVALIDARG;
  521. TraceError("CUPnPAutomationProxy::"
  522. "GetIntputArgumentNamesAndTypes(): "
  523. "No such action",
  524. hr);
  525. }
  526. // If successful, copy to the output, otherwise, clean up.
  527. if (SUCCEEDED(hr))
  528. {
  529. *pcInArguments = cInArguments;
  530. *prgbstrNames = rgbstrNames;
  531. *prgbstrTypes = rgbstrTypes;
  532. }
  533. else
  534. {
  535. if (rgbstrNames)
  536. {
  537. for (DWORD i = 0; i < cInArguments; i++)
  538. {
  539. if (rgbstrNames[i])
  540. {
  541. SysFreeString(rgbstrNames[i]);
  542. rgbstrNames[i] = NULL;
  543. }
  544. }
  545. CoTaskMemFree(rgbstrNames);
  546. rgbstrNames = NULL;
  547. }
  548. if (rgbstrTypes)
  549. {
  550. for (DWORD i = 0; i < cInArguments; i++)
  551. {
  552. if (rgbstrTypes[i])
  553. {
  554. SysFreeString(rgbstrTypes[i]);
  555. rgbstrTypes[i] = NULL;
  556. }
  557. }
  558. CoTaskMemFree(rgbstrTypes);
  559. rgbstrTypes = NULL;
  560. }
  561. cInArguments = 0;
  562. }
  563. Cleanup:
  564. TraceError("CUPnPAutomationProxy::GetInputArgumentNamesAndTypes(): "
  565. "Exiting",
  566. hr);
  567. return hr;
  568. }
  569. STDMETHODIMP
  570. CUPnPAutomationProxy::GetOutputArgumentNamesAndTypes(
  571. /*[in]*/ LPWSTR pszActionName,
  572. /*[out]*/ DWORD * pcOutArguments,
  573. /*[out]*/ BSTR ** prgbstrNames,
  574. /*[out]*/ BSTR ** prgbstrTypes)
  575. {
  576. HRESULT hr = S_OK;
  577. DWORD cOutArguments = 0;
  578. BSTR * rgbstrNames = NULL;
  579. BSTR * rgbstrTypes = NULL;
  580. UPNP_ACTION * pua = NULL;
  581. hr = HrIsAllowedCOMCallLocality((CALL_LOCALITY) CALL_LOCALITY_INPROC );
  582. if (FAILED(hr))
  583. {
  584. TraceError("HrIsAllowedCOMCallLocality failed !",hr);
  585. goto Cleanup;
  586. }
  587. Assert(m_fInitialized);
  588. pua = LookupActionByName(pszActionName);
  589. if (pua)
  590. {
  591. // Allocate arrays for the names and data types.
  592. cOutArguments = pua->cOutArgs;
  593. if (cOutArguments > 0)
  594. {
  595. rgbstrNames = (BSTR *) CoTaskMemAlloc(cOutArguments * sizeof(BSTR));
  596. rgbstrTypes = (BSTR *) CoTaskMemAlloc(cOutArguments * sizeof(BSTR));
  597. if (rgbstrNames && rgbstrTypes)
  598. {
  599. for (DWORD i = 0; SUCCEEDED(hr) && (i < cOutArguments); i++)
  600. {
  601. UPNP_STATE_VARIABLE * pusvRelated = NULL;
  602. rgbstrNames[i] = SysAllocString(pua->rgOutArgs[i].bstrName);
  603. pusvRelated = pua->rgOutArgs[i].pusvRelated;
  604. Assert(pusvRelated);
  605. rgbstrTypes[i] = SysAllocString(pusvRelated->bstrDataType);
  606. if (rgbstrNames[i] && rgbstrTypes[i])
  607. {
  608. TraceTag(ttidAutomationProxy,
  609. "CUPnPAutomationProxy::"
  610. "GetOutputArgumentNamesAndTypes(): "
  611. "Successfully copied output argument %S "
  612. "of type %S",
  613. rgbstrNames[i],
  614. rgbstrTypes[i]);
  615. }
  616. else
  617. {
  618. hr = E_OUTOFMEMORY;
  619. TraceError("CUPnPAutomationProxy::"
  620. "GetOutputArgumentNamesAndTypes(): "
  621. "Failed to allocate argument name and/or type",
  622. hr);
  623. }
  624. }
  625. }
  626. else
  627. {
  628. hr = E_OUTOFMEMORY;
  629. TraceError("CUPnPAutomationProxy::"
  630. "GetOutputArgumentNamesAndTypes(): "
  631. "Failed to allocate output arrays",
  632. hr);
  633. }
  634. }
  635. }
  636. else
  637. {
  638. hr = E_INVALIDARG;
  639. TraceError("CUPnPAutomationProxy::"
  640. "GetOutputArgumentNamesAndTypes(): "
  641. "No such action",
  642. hr);
  643. }
  644. // If successful, copy to the output, otherwise, clean up.
  645. if (SUCCEEDED(hr))
  646. {
  647. *pcOutArguments = cOutArguments;
  648. *prgbstrNames = rgbstrNames;
  649. *prgbstrTypes = rgbstrTypes;
  650. }
  651. else
  652. {
  653. if (rgbstrNames)
  654. {
  655. for (DWORD i = 0; i < cOutArguments; i++)
  656. {
  657. if (rgbstrNames[i])
  658. {
  659. SysFreeString(rgbstrNames[i]);
  660. rgbstrNames[i] = NULL;
  661. }
  662. }
  663. CoTaskMemFree(rgbstrNames);
  664. rgbstrNames = NULL;
  665. }
  666. if (rgbstrTypes)
  667. {
  668. for (DWORD i = 0; i < cOutArguments; i++)
  669. {
  670. if (rgbstrTypes[i])
  671. {
  672. SysFreeString(rgbstrTypes[i]);
  673. rgbstrTypes[i] = NULL;
  674. }
  675. }
  676. CoTaskMemFree(rgbstrTypes);
  677. rgbstrTypes = NULL;
  678. }
  679. cOutArguments = 0;
  680. }
  681. TraceError("CUPnPAutomationProxy::GetOutputArgumentNamesAndTypes(): "
  682. "Exiting",
  683. hr);
  684. Cleanup:
  685. return hr;
  686. }
  687. //+---------------------------------------------------------------------------
  688. //
  689. // Member: CUPnPAutomationProxy::FreeVariable
  690. //
  691. // Purpose: Frees resources used by a state variable structure
  692. //
  693. // Arguments:
  694. // pVariable [in] Address of the structure to free
  695. //
  696. // Returns:
  697. // (none)
  698. //
  699. // Author: spather 2000/09/26
  700. //
  701. // Notes:
  702. // This frees only the memory used by the fields of the structure, not
  703. // the structure itself.
  704. //
  705. VOID
  706. CUPnPAutomationProxy::FreeVariable(UPNP_STATE_VARIABLE * pVariable)
  707. {
  708. if (pVariable->bstrName)
  709. {
  710. SysFreeString(pVariable->bstrName);
  711. pVariable->bstrName = NULL;
  712. }
  713. if (pVariable->bstrDataType)
  714. {
  715. SysFreeString(pVariable->bstrDataType);
  716. pVariable->bstrDataType = NULL;
  717. }
  718. }
  719. //+---------------------------------------------------------------------------
  720. //
  721. // Member: CUPnPAutomationProxy::FreeAction
  722. //
  723. // Purpose: Frees resources used by an action structure
  724. //
  725. // Arguments:
  726. // pAction [in] Address of the structure to free
  727. //
  728. // Returns:
  729. // (none)
  730. //
  731. // Author: spather 2000/09/26
  732. //
  733. // Notes:
  734. // This frees only the memory used by the fields of the structure, not
  735. // the structure itself.
  736. //
  737. VOID
  738. CUPnPAutomationProxy::FreeAction(UPNP_ACTION * pAction)
  739. {
  740. if (pAction->bstrName)
  741. {
  742. SysFreeString(pAction->bstrName);
  743. pAction->bstrName = NULL;
  744. }
  745. if (pAction->rgInArgs)
  746. {
  747. for (DWORD i = 0; i < pAction->cInArgs; i++)
  748. {
  749. FreeArgument(&pAction->rgInArgs[i]);
  750. }
  751. delete [] pAction->rgInArgs;
  752. pAction->rgInArgs = NULL;
  753. }
  754. pAction->cInArgs = 0;
  755. if (pAction->rgOutArgs)
  756. {
  757. for (DWORD i = 0; i < pAction->cOutArgs; i++)
  758. {
  759. FreeArgument(&pAction->rgOutArgs[i]);
  760. }
  761. delete [] pAction->rgOutArgs;
  762. pAction->rgOutArgs = NULL;
  763. }
  764. pAction->cOutArgs = 0;
  765. pAction->puaRetVal = NULL;
  766. }
  767. //+---------------------------------------------------------------------------
  768. //
  769. // Member: CUPnPAutomationProxy::FreeArgument
  770. //
  771. // Purpose: Frees resources used by an argument structure
  772. //
  773. // Arguments:
  774. // pArg [in] Address of the structure to free
  775. //
  776. // Returns:
  777. // (none)
  778. //
  779. // Author: spather 2000/09/26
  780. //
  781. // Notes:
  782. // This frees only the memory used by the fields of the structure, not
  783. // the structure itself.
  784. //
  785. VOID
  786. CUPnPAutomationProxy::FreeArgument(UPNP_ARGUMENT * pArg)
  787. {
  788. if (pArg->bstrName)
  789. {
  790. SysFreeString(pArg->bstrName);
  791. pArg->bstrName = NULL;
  792. }
  793. pArg->pusvRelated = NULL;
  794. }
  795. //+---------------------------------------------------------------------------
  796. //
  797. // Member: CUPnPAutomationProxy::FreeVariableTable
  798. //
  799. // Purpose: Frees the Automation Proxy object's variable table.
  800. //
  801. // Arguments:
  802. // (none)
  803. //
  804. // Returns:
  805. // (none)
  806. //
  807. // Author: spather 2000/09/26
  808. //
  809. // Notes:
  810. //
  811. VOID
  812. CUPnPAutomationProxy::FreeVariableTable()
  813. {
  814. for (DWORD i = 0; i < m_cVariables; i++)
  815. {
  816. FreeVariable(&m_rgVariables[i]);
  817. }
  818. delete [] m_rgVariables;
  819. m_rgVariables = NULL;
  820. m_cVariables = 0;
  821. m_cEventedVariables = 0;
  822. }
  823. //+---------------------------------------------------------------------------
  824. //
  825. // Member: CUPnPAutomationProxy::FreeVariableTable
  826. //
  827. // Purpose: Frees the Automation Proxy object's action table.
  828. //
  829. // Arguments:
  830. // (none)
  831. //
  832. // Returns:
  833. // (none)
  834. //
  835. // Author: spather 2000/09/26
  836. //
  837. // Notes:
  838. //
  839. VOID
  840. CUPnPAutomationProxy::FreeActionTable()
  841. {
  842. for (DWORD i = 0; i < m_cActions; i++)
  843. {
  844. FreeAction(&m_rgActions[i]);
  845. }
  846. delete [] m_rgActions;
  847. m_rgActions = NULL;
  848. m_cActions = 0;
  849. }
  850. VOID
  851. CUPnPAutomationProxy::FreeControlResponse(
  852. UPNP_CONTROL_RESPONSE * pucresp)
  853. {
  854. if (pucresp->bstrActionName)
  855. {
  856. SysFreeString(pucresp->bstrActionName);
  857. pucresp->bstrActionName = NULL;
  858. }
  859. UPNP_CONTROL_RESPONSE_DATA * pucrd = &pucresp->ucrData;
  860. if (pucresp->fSucceeded)
  861. {
  862. if (pucrd->Success.rgvarOutputArgs)
  863. {
  864. for (DWORD i = 0; i < pucrd->Success.cOutputArgs; i++)
  865. {
  866. VariantClear(&pucrd->Success.rgvarOutputArgs[i]);
  867. }
  868. CoTaskMemFree(pucrd->Success.rgvarOutputArgs);
  869. pucrd->Success.rgvarOutputArgs = NULL;
  870. pucrd->Success.cOutputArgs = 0;
  871. }
  872. }
  873. else
  874. {
  875. if (pucrd->Fault.bstrFaultCode)
  876. {
  877. SysFreeString(pucrd->Fault.bstrFaultCode);
  878. pucrd->Fault.bstrFaultCode = NULL;
  879. }
  880. if (pucrd->Fault.bstrFaultString)
  881. {
  882. SysFreeString(pucrd->Fault.bstrFaultString);
  883. pucrd->Fault.bstrFaultString = NULL;
  884. }
  885. if (pucrd->Fault.bstrUPnPErrorCode)
  886. {
  887. SysFreeString(pucrd->Fault.bstrUPnPErrorCode);
  888. pucrd->Fault.bstrUPnPErrorCode = NULL;
  889. }
  890. if (pucrd->Fault.bstrUPnPErrorString)
  891. {
  892. SysFreeString(pucrd->Fault.bstrUPnPErrorString);
  893. pucrd->Fault.bstrUPnPErrorString = NULL;
  894. }
  895. }
  896. }
  897. HRESULT
  898. CUPnPAutomationProxy::HrProcessServiceDescription(
  899. IN LPWSTR pszSvcDescription)
  900. {
  901. HRESULT hr = S_OK;
  902. IXMLDOMDocument * pxddSvcDesc = NULL;
  903. TraceTag(ttidAutomationProxy,
  904. "CUPnPAutomationProxy::"
  905. "HrProcessServiceDescription(): "
  906. "Processing service description:\n"
  907. "%S",
  908. pszSvcDescription);
  909. hr = CoCreateInstance(CLSID_DOMDocument30,
  910. NULL,
  911. CLSCTX_INPROC_SERVER,
  912. IID_IXMLDOMDocument,
  913. (void **) &pxddSvcDesc);
  914. if (SUCCEEDED(hr))
  915. {
  916. BSTR bstrSvcDesc = NULL;
  917. Assert(pxddSvcDesc);
  918. bstrSvcDesc = SysAllocString(pszSvcDescription);
  919. if (bstrSvcDesc)
  920. {
  921. hr = pxddSvcDesc->put_async(VARIANT_FALSE);
  922. if (SUCCEEDED(hr))
  923. {
  924. VARIANT_BOOL vbSuccess = VARIANT_FALSE;
  925. pxddSvcDesc->put_resolveExternals(VARIANT_FALSE);
  926. hr = pxddSvcDesc->loadXML(bstrSvcDesc, &vbSuccess);
  927. if (SUCCEEDED(hr) && (VARIANT_TRUE == vbSuccess))
  928. {
  929. IXMLDOMElement * pxdeRoot = NULL;
  930. hr = pxddSvcDesc->get_documentElement(&pxdeRoot);
  931. if (S_OK == hr)
  932. {
  933. Assert(pxdeRoot);
  934. hr = HrValidateServiceDescription(pxdeRoot);
  935. if (SUCCEEDED(hr))
  936. {
  937. hr = HrBuildTablesFromServiceDescription(pxdeRoot);
  938. if (SUCCEEDED(hr))
  939. {
  940. TraceTag(ttidAutomationProxy,
  941. "CUPnPAutomationProxy::"
  942. "HrProcessServiceDescription(): "
  943. "Successfully built tables from "
  944. "service description",
  945. hr);
  946. }
  947. else
  948. {
  949. TraceError("CUPnPAutomationProxy::"
  950. "HrProcessServiceDescription(): "
  951. "Could not build tables from "
  952. "service description",
  953. hr);
  954. }
  955. }
  956. else
  957. {
  958. TraceError("CUPnPAutomationProxy::"
  959. "HrProcessServiceDescription(): "
  960. "Could not validate service "
  961. "description",
  962. hr);
  963. }
  964. pxdeRoot->Release();
  965. }
  966. else
  967. {
  968. TraceError("CUPnPAutomationProxy::"
  969. "HrProcessServiceDescription(): "
  970. "Could not get document element",
  971. hr);
  972. }
  973. }
  974. else
  975. {
  976. TraceError("CUPnPAutomationProxy::"
  977. "HrProcessServiceDescription(): "
  978. "Failed to load XML",
  979. hr);
  980. }
  981. }
  982. else
  983. {
  984. TraceError("CUPnPAutomationProxy::"
  985. "HrProcessServiceDescription(): "
  986. "Could not set async property",
  987. hr);
  988. }
  989. SysFreeString(bstrSvcDesc);
  990. }
  991. else
  992. {
  993. hr = E_OUTOFMEMORY;
  994. TraceError("CUPnPAutomationProxy::HrProcessServiceDescription(): "
  995. "Could not allocate BSTR service description",
  996. hr);
  997. }
  998. pxddSvcDesc->Release();
  999. }
  1000. else
  1001. {
  1002. TraceError("CUPnPAutomationProxy::HrProcessServiceDescription(): "
  1003. "Could not create DOM document",
  1004. hr);
  1005. }
  1006. TraceError("CUPnPAutomationProxy::HrProcessServiceDescription(): "
  1007. "Exiting",
  1008. hr);
  1009. return hr;
  1010. }
  1011. HRESULT
  1012. CUPnPAutomationProxy::HrValidateServiceDescription(
  1013. IXMLDOMElement * pxdeRoot)
  1014. {
  1015. return S_OK;
  1016. }
  1017. HRESULT
  1018. CUPnPAutomationProxy::HrBuildTablesFromServiceDescription(
  1019. IXMLDOMElement * pxdeRoot)
  1020. {
  1021. HRESULT hr = S_OK;
  1022. IXMLDOMNode * pxdnRoot = NULL;
  1023. hr = pxdeRoot->QueryInterface(IID_IXMLDOMNode,
  1024. (void **) &pxdnRoot);
  1025. if (SUCCEEDED(hr))
  1026. {
  1027. IXMLDOMNode * pxdnSST = NULL;
  1028. LPCWSTR arypszTokens[] = {L"serviceStateTable"};
  1029. Assert(pxdnRoot);
  1030. // Get the <serviceStateTable> element and use it's children to
  1031. // build the variable table.
  1032. hr = HrGetNestedChildElement(pxdnRoot,
  1033. arypszTokens,
  1034. 1,
  1035. &pxdnSST);
  1036. if (SUCCEEDED(hr))
  1037. {
  1038. IXMLDOMNodeList * pxdnlStateVars = NULL;
  1039. Assert(pxdnSST);
  1040. // Get the list of <stateVariable> nodes.
  1041. hr = pxdnSST->get_childNodes(&pxdnlStateVars);
  1042. if (SUCCEEDED(hr))
  1043. {
  1044. hr = HrBuildVariableTable(pxdnlStateVars);
  1045. if (SUCCEEDED(hr))
  1046. {
  1047. TraceTag(ttidAutomationProxy,
  1048. "CUPnPAutomationProxy::"
  1049. "HrBuildTablesFromServiceDescription(): "
  1050. "Successfully built variable table");
  1051. }
  1052. else
  1053. {
  1054. TraceError("CUPnPAutomationProxy::"
  1055. "HrBuildTablesFromServiceDescription(): "
  1056. "Failed to build variable table",
  1057. hr);
  1058. }
  1059. pxdnlStateVars->Release();
  1060. }
  1061. else
  1062. {
  1063. TraceError("CUPnPAutomationProxy::"
  1064. "HrBuildTablesFromServiceDescription(): "
  1065. "Failed to get <stateVariable> elements",
  1066. hr);
  1067. }
  1068. pxdnSST->Release();
  1069. }
  1070. else
  1071. {
  1072. TraceError("CUPnPAutomationProxy::"
  1073. "HrBuildTablesFromServiceDescription(): "
  1074. "Failed to get <serviceStateTable> element",
  1075. hr);
  1076. }
  1077. // If the above succeeded, we'll now build the action
  1078. // table.
  1079. if (SUCCEEDED(hr))
  1080. {
  1081. IXMLDOMNode * pxdnActionList = NULL;
  1082. LPCWSTR arypszALTokens[] = {L"actionList"};
  1083. Assert(pxdnRoot);
  1084. // Get the <actionList> element and use it's children to
  1085. // build the action table.
  1086. hr = HrGetNestedChildElement(pxdnRoot,
  1087. arypszALTokens,
  1088. 1,
  1089. &pxdnActionList);
  1090. if (SUCCEEDED(hr) && hr != S_FALSE)
  1091. {
  1092. IXMLDOMNodeList * pxdnlActions = NULL;
  1093. Assert(pxdnActionList);
  1094. // Get the list of <action> nodes.
  1095. hr = pxdnActionList->get_childNodes(&pxdnlActions);
  1096. if (SUCCEEDED(hr))
  1097. {
  1098. hr = HrBuildActionTable(pxdnlActions);
  1099. if (SUCCEEDED(hr))
  1100. {
  1101. TraceTag(ttidAutomationProxy,
  1102. "CUPnPAutomationProxy::"
  1103. "HrBuildTablesFromServiceDescription(): "
  1104. "Successfully built action table");
  1105. }
  1106. else
  1107. {
  1108. TraceError("CUPnPAutomationProxy::"
  1109. "HrBuildTablesFromServiceDescription(): "
  1110. "Failed to build action table",
  1111. hr);
  1112. }
  1113. pxdnlActions->Release();
  1114. }
  1115. else
  1116. {
  1117. TraceError("CUPnPAutomationProxy::"
  1118. "HrBuildTablesFromServiceDescription(): "
  1119. "Failed to get <action> elements",
  1120. hr);
  1121. }
  1122. pxdnActionList->Release();
  1123. }
  1124. else
  1125. {
  1126. TraceErrorOptional("CUPnPAutomationProxy::"
  1127. "HrBuildTablesFromServiceDescription(): "
  1128. "Failed to get <actionList> element",
  1129. hr, (S_FALSE == hr));
  1130. }
  1131. }
  1132. pxdnRoot->Release();
  1133. }
  1134. TraceError("CUPnPAutomationProxy::"
  1135. "HrBuildTablesFromServiceDescription(): "
  1136. "Exiting",
  1137. hr);
  1138. return hr;
  1139. }
  1140. HRESULT
  1141. CUPnPAutomationProxy::HrBuildVariableTable(
  1142. IXMLDOMNodeList * pxdnlStateVars)
  1143. {
  1144. HRESULT hr = S_OK;
  1145. LONG listLength = 0;
  1146. hr = pxdnlStateVars->get_length(&listLength);
  1147. if (SUCCEEDED(hr))
  1148. {
  1149. Assert(listLength > 0);
  1150. m_rgVariables = new UPNP_STATE_VARIABLE[listLength];
  1151. if (m_rgVariables)
  1152. {
  1153. ZeroMemory(m_rgVariables,
  1154. listLength * sizeof(UPNP_STATE_VARIABLE));
  1155. m_cVariables = 0;
  1156. m_cEventedVariables = 0;
  1157. for (long i = 0; SUCCEEDED(hr) && (i < listLength); i++)
  1158. {
  1159. IXMLDOMNode * pxdnStateVar = NULL;
  1160. hr = pxdnlStateVars->get_item(i, &pxdnStateVar);
  1161. if (SUCCEEDED(hr))
  1162. {
  1163. LPCWSTR rgszNameTokens[] = {L"name"};
  1164. Assert(pxdnStateVar);
  1165. // Get the "name" and "dataType" values.
  1166. hr = HrGetTextValueFromChildElement(pxdnStateVar,
  1167. rgszNameTokens,
  1168. 1,
  1169. &(m_rgVariables[i].bstrName));
  1170. if (SUCCEEDED(hr))
  1171. {
  1172. LPCWSTR rgszDataTypeTokens[] = {L"dataType"};
  1173. hr = HrGetTextValueFromChildElement(pxdnStateVar,
  1174. rgszDataTypeTokens,
  1175. 1,
  1176. &(m_rgVariables[i].bstrDataType));
  1177. if (SUCCEEDED(hr))
  1178. {
  1179. BSTR bstrSendEvents = NULL;
  1180. TraceTag(ttidAutomationProxy,
  1181. "HrBuildVariableTable(): "
  1182. "Variable name %S and data type %S",
  1183. m_rgVariables[i].bstrName,
  1184. m_rgVariables[i].bstrDataType);
  1185. hr = HrGetTextValueFromAttribute(pxdnStateVar,
  1186. L"sendEvents",
  1187. &bstrSendEvents);
  1188. if (SUCCEEDED(hr))
  1189. {
  1190. if (NULL == bstrSendEvents)
  1191. {
  1192. hr = S_OK;
  1193. m_rgVariables[i].fNonEvented = FALSE;
  1194. m_cEventedVariables++;
  1195. TraceTag(ttidAutomationProxy,
  1196. "HrBuildVariableTable(): "
  1197. "Variable %S did not have a "
  1198. "sendEvents attribute - treating "
  1199. "it as evented",
  1200. m_rgVariables[i].bstrName);
  1201. }
  1202. else
  1203. {
  1204. if (0 == lstrcmpW(bstrSendEvents, L"yes"))
  1205. {
  1206. m_rgVariables[i].fNonEvented = FALSE;
  1207. m_cEventedVariables++;
  1208. TraceTag(ttidAutomationProxy,
  1209. "HrBuildVariableTable(): "
  1210. "Variable %S is evented ",
  1211. m_rgVariables[i].bstrName);
  1212. }
  1213. else if (0 == lstrcmpW(bstrSendEvents, L"no"))
  1214. {
  1215. m_rgVariables[i].fNonEvented = TRUE;
  1216. TraceTag(ttidAutomationProxy,
  1217. "HrBuildVariableTable(): "
  1218. "Variable %S is non-evented ",
  1219. m_rgVariables[i].bstrName);
  1220. }
  1221. SysFreeString(bstrSendEvents);
  1222. }
  1223. }
  1224. else
  1225. {
  1226. TraceError("CUPnPAutomationProxy::"
  1227. "HrBuildVariableTable(): "
  1228. "Failed to get sendEvents attribute",
  1229. hr);
  1230. }
  1231. }
  1232. else
  1233. {
  1234. TraceError("CUPnPAutomationProxy::"
  1235. "HrBuildVariableTable(): "
  1236. "Failed to get variable data type",
  1237. hr);
  1238. }
  1239. }
  1240. else
  1241. {
  1242. TraceError("CUPnPAutomationProxy::"
  1243. "HrBuildVariableTable(): "
  1244. "Failed to get variable name",
  1245. hr);
  1246. }
  1247. pxdnStateVar->Release();
  1248. }
  1249. else
  1250. {
  1251. TraceError("CUPnPAutomationProxy::"
  1252. "HrBuildVariableTable(): "
  1253. "Failed to get list item",
  1254. hr);
  1255. }
  1256. if (SUCCEEDED(hr))
  1257. {
  1258. m_cVariables++;
  1259. }
  1260. else
  1261. {
  1262. FreeVariable(&m_rgVariables[i]);
  1263. }
  1264. }
  1265. }
  1266. else
  1267. {
  1268. hr = E_OUTOFMEMORY;
  1269. TraceError("CUPnPAutomationProxy::"
  1270. "HrBuildVariableTable(): "
  1271. "Failed to allocate variable table",
  1272. hr);
  1273. }
  1274. }
  1275. else
  1276. {
  1277. TraceError("CUPnPAutomationProxy::"
  1278. "HrBuildVariableTable(): "
  1279. "Failed to get list length",
  1280. hr);
  1281. }
  1282. // Got the names and data types, now just need to get the DISPIDs.
  1283. if (SUCCEEDED(hr))
  1284. {
  1285. for (DWORD i = 0; SUCCEEDED(hr) && (i < m_cVariables); i++)
  1286. {
  1287. hr = m_pdispService->GetIDsOfNames(IID_NULL,
  1288. &m_rgVariables[i].bstrName,
  1289. 1,
  1290. LOCALE_SYSTEM_DEFAULT,
  1291. &m_rgVariables[i].dispid);
  1292. if (SUCCEEDED(hr))
  1293. {
  1294. Assert(DISPID_UNKNOWN != m_rgVariables[i].dispid);
  1295. TraceTag(ttidAutomationProxy,
  1296. "CUPnPAutomationProxy::"
  1297. "HrBuildVariableTable(): "
  1298. "Variable %S has dispID %d",
  1299. m_rgVariables[i].bstrName,
  1300. m_rgVariables[i].dispid);
  1301. }
  1302. else
  1303. {
  1304. TraceError("CUPnPAutomationProxy::"
  1305. "HrBuildVariableTable(): "
  1306. "Failed to get dispId",
  1307. hr);
  1308. }
  1309. }
  1310. }
  1311. TraceError("CUPnPAutomationProxy::"
  1312. "HrBuildVariableTable(): "
  1313. "Exiting",
  1314. hr);
  1315. return hr;
  1316. }
  1317. HRESULT
  1318. CUPnPAutomationProxy::HrBuildActionTable(
  1319. IXMLDOMNodeList * pxdnlActions)
  1320. {
  1321. HRESULT hr = S_OK;
  1322. LONG listLength = 0;
  1323. hr = pxdnlActions->get_length(&listLength);
  1324. if (SUCCEEDED(hr))
  1325. {
  1326. Assert(listLength > 0);
  1327. m_rgActions = new UPNP_ACTION[listLength];
  1328. if (m_rgActions)
  1329. {
  1330. ZeroMemory(m_rgActions,
  1331. listLength * sizeof(UPNP_ACTION));
  1332. m_cActions = 0;
  1333. for (long i = 0; SUCCEEDED(hr) && (i < listLength); i++)
  1334. {
  1335. IXMLDOMNode * pxdnAction = NULL;
  1336. hr = pxdnlActions->get_item(i, &pxdnAction);
  1337. if (SUCCEEDED(hr))
  1338. {
  1339. LPCWSTR rgszNameTokens[] = {L"name"};
  1340. Assert(pxdnAction);
  1341. // Get the "name" value.
  1342. hr = HrGetTextValueFromChildElement(pxdnAction,
  1343. rgszNameTokens,
  1344. 1,
  1345. &(m_rgActions[i].bstrName));
  1346. if (SUCCEEDED(hr))
  1347. {
  1348. // Initialize arguments.
  1349. hr = HrBuildArgumentLists(pxdnAction,
  1350. &m_rgActions[i]);
  1351. if (SUCCEEDED(hr))
  1352. {
  1353. TraceTag(ttidAutomationProxy,
  1354. "HrBuildActionTable(): "
  1355. "Action %S initialized",
  1356. m_rgActions[i].bstrName);
  1357. }
  1358. else
  1359. {
  1360. TraceError("CUPnPAutomationProxy::"
  1361. "HrBuildActionTable(): "
  1362. "Failed to build argument lists",
  1363. hr);
  1364. }
  1365. }
  1366. else
  1367. {
  1368. TraceError("CUPnPAutomationProxy::"
  1369. "HrBuildActionTable(): "
  1370. "Failed to get action name",
  1371. hr);
  1372. }
  1373. pxdnAction->Release();
  1374. }
  1375. else
  1376. {
  1377. TraceError("CUPnPAutomationProxy::"
  1378. "HrBuildActionTable(): "
  1379. "Failed to get list item",
  1380. hr);
  1381. }
  1382. if (SUCCEEDED(hr))
  1383. {
  1384. m_cActions++;
  1385. }
  1386. else
  1387. {
  1388. FreeAction(&m_rgActions[i]);
  1389. }
  1390. }
  1391. }
  1392. else
  1393. {
  1394. hr = E_OUTOFMEMORY;
  1395. TraceError("CUPnPAutomationProxy::"
  1396. "HrBuildActionTable(): "
  1397. "Failed to allocate action table",
  1398. hr);
  1399. }
  1400. }
  1401. else
  1402. {
  1403. TraceError("CUPnPAutomationProxy::"
  1404. "HrBuildActionTable(): "
  1405. "Failed to get list length",
  1406. hr);
  1407. }
  1408. // Got the names and arguments, now just need to get the DISPIDs.
  1409. if (SUCCEEDED(hr))
  1410. {
  1411. for (DWORD i = 0; SUCCEEDED(hr) && (i < m_cActions); i++)
  1412. {
  1413. hr = m_pdispService->GetIDsOfNames(IID_NULL,
  1414. &m_rgActions[i].bstrName,
  1415. 1,
  1416. LOCALE_SYSTEM_DEFAULT,
  1417. &m_rgActions[i].dispid);
  1418. if (SUCCEEDED(hr))
  1419. {
  1420. Assert(DISPID_UNKNOWN != m_rgActions[i].dispid);
  1421. TraceTag(ttidAutomationProxy,
  1422. "CUPnPAutomationProxy::"
  1423. "HrBuildActionTable(): "
  1424. "Action %S has dispID %d",
  1425. m_rgActions[i].bstrName,
  1426. m_rgActions[i].dispid);
  1427. }
  1428. else
  1429. {
  1430. TraceError("CUPnPAutomationProxy::"
  1431. "HrBuildActionTable(): "
  1432. "Failed to get dispId",
  1433. hr);
  1434. }
  1435. }
  1436. }
  1437. TraceError("CUPnPAutomationProxy::HrBuildActionTable(): "
  1438. "Exiting",
  1439. hr);
  1440. return hr;
  1441. }
  1442. HRESULT
  1443. CUPnPAutomationProxy::HrBuildArgumentLists(
  1444. IXMLDOMNode * pxdnAction,
  1445. UPNP_ACTION * pAction)
  1446. {
  1447. HRESULT hr = S_OK;
  1448. IXMLDOMNode * pxdnArgList = NULL;
  1449. LPCWSTR arypszTokens[] = {L"argumentList"};
  1450. Assert(pxdnAction);
  1451. Assert(pAction);
  1452. hr = HrGetNestedChildElement(pxdnAction, arypszTokens, 1, &pxdnArgList);
  1453. if (SUCCEEDED(hr))
  1454. {
  1455. if (pxdnArgList)
  1456. {
  1457. IXMLDOMNodeList * pxdnlArgs = NULL;
  1458. hr = pxdnArgList->get_childNodes(&pxdnlArgs);
  1459. if (SUCCEEDED(hr))
  1460. {
  1461. DWORD cInArgs = 0;
  1462. DWORD cOutArgs = 0;
  1463. hr = HrCountInAndOutArgs(pxdnlArgs, &cInArgs, &cOutArgs);
  1464. if (SUCCEEDED(hr))
  1465. {
  1466. TraceTag(ttidAutomationProxy,
  1467. "CUPnPAutomationProxy::HrBuildArgumentLists(): "
  1468. "Action %S has %d input arguments and "
  1469. "%d output arguments",
  1470. pAction->bstrName,
  1471. cInArgs,
  1472. cOutArgs);
  1473. // Allocate memory for the argument lists.
  1474. if (cInArgs > 0)
  1475. {
  1476. pAction->rgInArgs = new UPNP_ARGUMENT[cInArgs];
  1477. if (pAction->rgInArgs)
  1478. {
  1479. pAction->cInArgs = cInArgs;
  1480. ZeroMemory(pAction->rgInArgs,
  1481. cInArgs * sizeof(UPNP_ARGUMENT));
  1482. }
  1483. else
  1484. {
  1485. hr = E_OUTOFMEMORY;
  1486. TraceError("CUPnPAutomationProxy::"
  1487. "HrBuildArgumentLists(): "
  1488. "Failed to allocate memory for input "
  1489. "arguments",
  1490. hr);
  1491. }
  1492. }
  1493. else
  1494. {
  1495. pAction->cInArgs = 0;
  1496. pAction->rgInArgs = NULL;
  1497. }
  1498. if (SUCCEEDED(hr))
  1499. {
  1500. if (cOutArgs > 0)
  1501. {
  1502. pAction->rgOutArgs = new UPNP_ARGUMENT[cOutArgs];
  1503. if (pAction->rgOutArgs)
  1504. {
  1505. pAction->cOutArgs = cOutArgs;
  1506. ZeroMemory(pAction->rgOutArgs,
  1507. cOutArgs * sizeof(UPNP_ARGUMENT));
  1508. }
  1509. else
  1510. {
  1511. hr = E_OUTOFMEMORY;
  1512. TraceError("CUPnPAutomationProxy::"
  1513. "HrBuildArgumentLists(): "
  1514. "Failed to allocate memory for out "
  1515. "arguments",
  1516. hr);
  1517. }
  1518. }
  1519. else
  1520. {
  1521. pAction->cOutArgs = 0;
  1522. pAction->rgOutArgs = NULL;
  1523. }
  1524. }
  1525. if (SUCCEEDED(hr))
  1526. {
  1527. hr = HrInitializeArguments(pxdnlArgs,
  1528. pAction);
  1529. if (SUCCEEDED(hr))
  1530. {
  1531. TraceTag(ttidAutomationProxy,
  1532. "CUPnPAutomationProxy::"
  1533. "HrBuildArgumentLists(): "
  1534. "Successfully initialized arguments");
  1535. }
  1536. else
  1537. {
  1538. TraceError("CUPnPAutomationProxy::"
  1539. "HrBuildArgumentLists(): "
  1540. "Failed to initialize arguments",
  1541. hr);
  1542. }
  1543. }
  1544. // If anything above failed, pAction structure will
  1545. // be cleaned up on return from this function.
  1546. }
  1547. pxdnlArgs->Release();
  1548. }
  1549. else
  1550. {
  1551. TraceError("CUPnPAutomationProxy::HrBuildArgumentLists(): "
  1552. "Failed to get <argumentList> children",
  1553. hr);
  1554. }
  1555. pxdnArgList->Release();
  1556. }
  1557. else
  1558. {
  1559. TraceTag(ttidAutomationProxy,
  1560. "CUPnPAutomationProxy::HrBuildArgumentLists(): "
  1561. "Action %S does not have any arguments",
  1562. pAction->bstrName);
  1563. pAction->cInArgs = 0;
  1564. pAction->rgInArgs = NULL;
  1565. pAction->cOutArgs = 0;
  1566. pAction->rgOutArgs = NULL;
  1567. pAction->puaRetVal = NULL;
  1568. // Fix up the return value.
  1569. hr = S_OK;
  1570. }
  1571. }
  1572. else
  1573. {
  1574. TraceError("CUPnPAutomationProxy::HrBuildArgumentLists(): "
  1575. "Failed to get <argumentList> element",
  1576. hr);
  1577. }
  1578. TraceHr(ttidError, FAL, hr, (hr == S_FALSE),
  1579. "CUPnPAutomationProxy::HrBuildArgumentLists");
  1580. return hr;
  1581. }
  1582. HRESULT
  1583. CUPnPAutomationProxy::HrCountInAndOutArgs(
  1584. IXMLDOMNodeList * pxdnlArgs,
  1585. DWORD * pcInArgs,
  1586. DWORD * pcOutArgs)
  1587. {
  1588. HRESULT hr = S_OK;
  1589. LONG listLength = 0;
  1590. DWORD cInArgs = 0;
  1591. DWORD cOutArgs = 0;
  1592. Assert(pxdnlArgs);
  1593. Assert(pcInArgs);
  1594. Assert(pcOutArgs);
  1595. hr = pxdnlArgs->get_length(&listLength);
  1596. if (SUCCEEDED(hr))
  1597. {
  1598. Assert(listLength > 0);
  1599. // Loop through the list of <argument> elements and read each one's
  1600. // <direction> element.
  1601. for (LONG i = 0; SUCCEEDED(hr) && (i < listLength); i++)
  1602. {
  1603. IXMLDOMNode * pxdnArg = NULL;
  1604. hr = pxdnlArgs->get_item(i, &pxdnArg);
  1605. if (SUCCEEDED(hr))
  1606. {
  1607. LPCWSTR arypszTokens[] = {L"direction"};
  1608. BSTR bstrDirection = NULL;
  1609. hr = HrGetTextValueFromChildElement(pxdnArg,
  1610. arypszTokens,
  1611. 1,
  1612. &bstrDirection);
  1613. if (SUCCEEDED(hr) && hr != S_FALSE)
  1614. {
  1615. if (lstrcmpW(bstrDirection, L"in") == 0)
  1616. {
  1617. cInArgs++;
  1618. }
  1619. else if (lstrcmpW(bstrDirection, L"out") == 0)
  1620. {
  1621. cOutArgs++;
  1622. }
  1623. else
  1624. {
  1625. // Document has already been validated - <direction>
  1626. // should contain either "in" or "out". Should never
  1627. // be here.
  1628. AssertSz(FALSE,
  1629. "Validated direction element contained"
  1630. "invalid value");
  1631. }
  1632. SysFreeString(bstrDirection);
  1633. }
  1634. else
  1635. {
  1636. TraceError("CUPnPAutomationProxy::HrCountInAndOutArgs(): "
  1637. "Failed to get <direction> value",
  1638. hr);
  1639. }
  1640. pxdnArg->Release();
  1641. }
  1642. else
  1643. {
  1644. TraceError("CUPnPAutomationProxy::HrCountInAndOutArgs(): "
  1645. "Failed to get list item",
  1646. hr);
  1647. }
  1648. }
  1649. }
  1650. else
  1651. {
  1652. TraceError("CUPnPAutomationProxy::HrCountInAndOutArgs(): "
  1653. "Failed to get list length",
  1654. hr);
  1655. }
  1656. // If everything succeeded, return counts through out parameters.
  1657. if (SUCCEEDED(hr))
  1658. {
  1659. *pcInArgs = cInArgs;
  1660. *pcOutArgs = cOutArgs;
  1661. }
  1662. TraceError("CUPnPAutomationProxy::HrCountInAndOutArgs(): "
  1663. "Exiting",
  1664. hr);
  1665. return hr;
  1666. }
  1667. HRESULT
  1668. CUPnPAutomationProxy::HrInitializeArguments(
  1669. IXMLDOMNodeList * pxdnlArgs,
  1670. UPNP_ACTION * pAction)
  1671. {
  1672. HRESULT hr = S_OK;
  1673. Assert(pxdnlArgs);
  1674. Assert(pAction);
  1675. // There should either be some input or some output arguments.
  1676. // For both input and output arguments, if there are any, an
  1677. // array should be allocated for them.
  1678. Assert(pAction->cInArgs || pAction->cOutArgs);
  1679. Assert(FImplies(pAction->cInArgs, pAction->rgInArgs));
  1680. Assert(FImplies(pAction->cOutArgs, pAction->rgOutArgs));
  1681. // In arguments must be declared before out arguments, so we can assume
  1682. // they are at the front of the list.
  1683. for (DWORD i = 0; SUCCEEDED(hr) && (i < pAction->cInArgs); i++)
  1684. {
  1685. LONG lIndex = (LONG) i;
  1686. IXMLDOMNode * pxdnArg = NULL;
  1687. hr = pxdnlArgs->get_item(lIndex, &pxdnArg);
  1688. if (SUCCEEDED(hr))
  1689. {
  1690. UPNP_ARGUMENT * puaCurrent = &pAction->rgInArgs[i];
  1691. LPCWSTR arypszNameTokens[] = {L"name"};
  1692. Assert(pxdnArg);
  1693. hr = HrGetTextValueFromChildElement(pxdnArg,
  1694. arypszNameTokens,
  1695. 1,
  1696. &puaCurrent->bstrName);
  1697. if (SUCCEEDED(hr))
  1698. {
  1699. LPCWSTR arypszRSVTokens[] = {L"relatedStateVariable"};
  1700. BSTR bstrRelStateVar = NULL;
  1701. TraceTag(ttidAutomationProxy,
  1702. "CUPnPAutomationProxy::HrInitializeArguments(): "
  1703. "Initializing argument %S",
  1704. puaCurrent->bstrName);
  1705. hr = HrGetTextValueFromChildElement(pxdnArg,
  1706. arypszRSVTokens,
  1707. 1,
  1708. &bstrRelStateVar);
  1709. if (SUCCEEDED(hr))
  1710. {
  1711. UPNP_STATE_VARIABLE * pusvRelated = NULL;
  1712. TraceTag(ttidAutomationProxy,
  1713. "CUPnPAutomationProxy::HrInitializeArguments(): "
  1714. "Argument %S is related to state variable %S",
  1715. puaCurrent->bstrName,
  1716. bstrRelStateVar);
  1717. pusvRelated = LookupVariableByName(bstrRelStateVar);
  1718. if (pusvRelated)
  1719. {
  1720. puaCurrent->pusvRelated = pusvRelated;
  1721. }
  1722. else
  1723. {
  1724. puaCurrent->pusvRelated = NULL;
  1725. hr = E_INVALIDARG;
  1726. TraceError("CUPnPAutomationProxy::HrInitializeArguments(): "
  1727. "Failed to find related state variable",
  1728. hr);
  1729. }
  1730. SysFreeString(bstrRelStateVar);
  1731. }
  1732. else
  1733. {
  1734. TraceError("CUPnPAutomationProxy::HrInitializeArguments(): "
  1735. "Failed to get <relatedStateVariable> value",
  1736. hr);
  1737. }
  1738. }
  1739. else
  1740. {
  1741. TraceError("CUPnPAutomationProxy::HrInitializeArguments(): "
  1742. "Failed to get <name> value",
  1743. hr);
  1744. }
  1745. pxdnArg->Release();
  1746. }
  1747. else
  1748. {
  1749. TraceError("CUPnPAutomationProxy::HrInitializeArguments(): "
  1750. "Failed to get list item",
  1751. hr);
  1752. }
  1753. }
  1754. // Now get the out arguments.
  1755. for (DWORD i = 0; SUCCEEDED(hr) && (i < pAction->cOutArgs); i++)
  1756. {
  1757. LONG lIndex = (LONG) (pAction->cInArgs + i);
  1758. IXMLDOMNode * pxdnArg = NULL;
  1759. hr = pxdnlArgs->get_item(lIndex, &pxdnArg);
  1760. if (SUCCEEDED(hr))
  1761. {
  1762. UPNP_ARGUMENT * puaCurrent = &pAction->rgOutArgs[i];
  1763. LPCWSTR arypszNameTokens[] = {L"name"};
  1764. Assert(pxdnArg);
  1765. hr = HrGetTextValueFromChildElement(pxdnArg,
  1766. arypszNameTokens,
  1767. 1,
  1768. &puaCurrent->bstrName);
  1769. if (SUCCEEDED(hr))
  1770. {
  1771. LPCWSTR arypszRSVTokens[] = {L"relatedStateVariable"};
  1772. BSTR bstrRelStateVar = NULL;
  1773. TraceTag(ttidAutomationProxy,
  1774. "CUPnPAutomationProxy::HrInitializeArguments(): "
  1775. "Initializing argument %S",
  1776. puaCurrent->bstrName);
  1777. hr = HrGetTextValueFromChildElement(pxdnArg,
  1778. arypszRSVTokens,
  1779. 1,
  1780. &bstrRelStateVar);
  1781. if (SUCCEEDED(hr))
  1782. {
  1783. UPNP_STATE_VARIABLE * pusvRelated = NULL;
  1784. TraceTag(ttidAutomationProxy,
  1785. "CUPnPAutomationProxy::HrInitializeArguments(): "
  1786. "Argument %S is related to state variable %S",
  1787. puaCurrent->bstrName,
  1788. bstrRelStateVar);
  1789. pusvRelated = LookupVariableByName(bstrRelStateVar);
  1790. if (pusvRelated)
  1791. {
  1792. LPCWSTR arypszRetvalTokens[] = {L"retval"};
  1793. IXMLDOMNode * pxdnRetVal = NULL;
  1794. puaCurrent->pusvRelated = pusvRelated;
  1795. hr = HrGetNestedChildElement(pxdnArg,
  1796. arypszRetvalTokens,
  1797. 1,
  1798. &pxdnRetVal);
  1799. if (SUCCEEDED(hr))
  1800. {
  1801. if (pxdnRetVal)
  1802. {
  1803. // This is the return value.
  1804. pAction->puaRetVal = puaCurrent;
  1805. }
  1806. }
  1807. else
  1808. {
  1809. TraceError("CUPnPAutomationProxy::"
  1810. "HrInitializeArguments(): "
  1811. "Failed get retval element",
  1812. hr);
  1813. }
  1814. }
  1815. else
  1816. {
  1817. puaCurrent->pusvRelated = NULL;
  1818. hr = E_INVALIDARG;
  1819. TraceError("CUPnPAutomationProxy::HrInitializeArguments(): "
  1820. "Failed to find related state variable",
  1821. hr);
  1822. }
  1823. SysFreeString(bstrRelStateVar);
  1824. }
  1825. else
  1826. {
  1827. TraceError("CUPnPAutomationProxy::HrInitializeArguments(): "
  1828. "Failed to get <relatedStateVariable> value",
  1829. hr);
  1830. }
  1831. }
  1832. else
  1833. {
  1834. TraceError("CUPnPAutomationProxy::HrInitializeArguments(): "
  1835. "Failed to get <name> value",
  1836. hr);
  1837. }
  1838. pxdnArg->Release();
  1839. }
  1840. else
  1841. {
  1842. TraceError("CUPnPAutomationProxy::HrInitializeArguments(): "
  1843. "Failed to get list item",
  1844. hr);
  1845. }
  1846. }
  1847. TraceHr(ttidError, FAL, hr, (hr == S_FALSE),
  1848. "CUPnPAutomationProxy::HrInitializeArguments");
  1849. return hr;
  1850. }
  1851. UPNP_STATE_VARIABLE *
  1852. CUPnPAutomationProxy::LookupVariableByDispID(DISPID dispid)
  1853. {
  1854. UPNP_STATE_VARIABLE * pusv = NULL;
  1855. for (DWORD i = 0; i < m_cVariables; i++)
  1856. {
  1857. if (m_rgVariables[i].dispid == dispid)
  1858. {
  1859. pusv = &m_rgVariables[i];
  1860. break;
  1861. }
  1862. }
  1863. if (pusv)
  1864. {
  1865. TraceTag(ttidAutomationProxy,
  1866. "CUPnPAutomationProxy::LookupVariableByDispID(): "
  1867. "DISPID %d corresponds to variable %S",
  1868. pusv->dispid,
  1869. pusv->bstrName);
  1870. }
  1871. else
  1872. {
  1873. TraceTag(ttidAutomationProxy,
  1874. "CUPnPAutomationProxy::LookupVariableByDispID(): "
  1875. "DISPID %d does not match any variable",
  1876. dispid);
  1877. }
  1878. return pusv;
  1879. }
  1880. UPNP_STATE_VARIABLE *
  1881. CUPnPAutomationProxy::LookupVariableByName(LPCWSTR pcszName)
  1882. {
  1883. UPNP_STATE_VARIABLE * pusv = NULL;
  1884. for (DWORD i = 0; i < m_cVariables; i++)
  1885. {
  1886. if (lstrcmpiW(m_rgVariables[i].bstrName, pcszName) == 0)
  1887. {
  1888. pusv = &m_rgVariables[i];
  1889. break;
  1890. }
  1891. }
  1892. if (pusv)
  1893. {
  1894. TraceTag(ttidAutomationProxy,
  1895. "CUPnPAutomationProxy::LookupVariableByName(): "
  1896. "Found %S in variable table",
  1897. pusv->bstrName);
  1898. }
  1899. else
  1900. {
  1901. TraceTag(ttidAutomationProxy,
  1902. "CUPnPAutomationProxy::LookupVariableByName(): "
  1903. "%S does not match any variable in variable table",
  1904. pcszName);
  1905. }
  1906. return pusv;
  1907. }
  1908. UPNP_ACTION *
  1909. CUPnPAutomationProxy::LookupActionByName(LPCWSTR pcszName)
  1910. {
  1911. UPNP_ACTION * pua = NULL;
  1912. for (DWORD i = 0; i < m_cActions; i++)
  1913. {
  1914. if (lstrcmpiW(m_rgActions[i].bstrName, pcszName) == 0)
  1915. {
  1916. pua = &m_rgActions[i];
  1917. break;
  1918. }
  1919. }
  1920. if (pua)
  1921. {
  1922. TraceTag(ttidAutomationProxy,
  1923. "CUPnPAutomationProxy::LookupActionByName(): "
  1924. "Found %S in action table",
  1925. pua->bstrName);
  1926. }
  1927. else
  1928. {
  1929. TraceTag(ttidAutomationProxy,
  1930. "CUPnPAutomationProxy::LookupActionByName(): "
  1931. "%S does not match any action in action table",
  1932. pcszName);
  1933. }
  1934. return pua;
  1935. }
  1936. HRESULT
  1937. CUPnPAutomationProxy::HrBuildFaultResponse(
  1938. UPNP_CONTROL_RESPONSE_DATA * pucrd,
  1939. LPCWSTR pcszFaultCode,
  1940. LPCWSTR pcszFaultString,
  1941. LPCWSTR pcszUPnPErrorCode,
  1942. LPCWSTR pcszUPnPErrorString)
  1943. {
  1944. HRESULT hr = S_OK;
  1945. pucrd->Fault.bstrFaultCode = SysAllocString(pcszFaultCode);
  1946. if (pucrd->Fault.bstrFaultCode)
  1947. {
  1948. pucrd->Fault.bstrFaultString = SysAllocString(pcszFaultString);
  1949. if (pucrd->Fault.bstrFaultString)
  1950. {
  1951. pucrd->Fault.bstrUPnPErrorCode = SysAllocString(pcszUPnPErrorCode);
  1952. if (pucrd->Fault.bstrUPnPErrorCode)
  1953. {
  1954. pucrd->Fault.bstrUPnPErrorString = SysAllocString(pcszUPnPErrorString);
  1955. if (pucrd->Fault.bstrUPnPErrorString)
  1956. {
  1957. TraceTag(ttidAutomationProxy,
  1958. "CUPnPAutomationProxy::HrBuildFaultResponse(): "
  1959. "Successfully built fault response: \n"
  1960. "\tFaultCode: %S\n"
  1961. "\tFaultString: %S\n"
  1962. "\tUPnPErrorCode: %S\n"
  1963. "\tUPnPErrorString: %S",
  1964. pucrd->Fault.bstrFaultCode,
  1965. pucrd->Fault.bstrFaultString,
  1966. pucrd->Fault.bstrUPnPErrorCode,
  1967. pucrd->Fault.bstrUPnPErrorString);
  1968. }
  1969. else
  1970. {
  1971. hr = E_OUTOFMEMORY;
  1972. TraceError("CUPnPAutomationProxy::HrBuildFaultResponse(): "
  1973. "Failed to allocate UPnP error string",
  1974. hr);
  1975. }
  1976. }
  1977. else
  1978. {
  1979. hr = E_OUTOFMEMORY;
  1980. TraceError("CUPnPAutomationProxy::HrBuildFaultResponse(): "
  1981. "Failed to allocate UPnP Error code string",
  1982. hr);
  1983. }
  1984. }
  1985. else
  1986. {
  1987. hr = E_OUTOFMEMORY;
  1988. TraceError("CUPnPAutomationProxy::HrBuildFaultResponse(): "
  1989. "Failed to allocate fault string",
  1990. hr);
  1991. }
  1992. }
  1993. else
  1994. {
  1995. hr = E_OUTOFMEMORY;
  1996. TraceError("CUPnPAutomationProxy::HrBuildFaultResponse(): "
  1997. "Failed to allocate fault code string",
  1998. hr);
  1999. }
  2000. TraceError("CUPnPAutomationProxy::HrBuildFaultResponse(): "
  2001. "Exiting",
  2002. hr);
  2003. return hr;
  2004. }
  2005. HRESULT
  2006. CUPnPAutomationProxy::HrVariantInitForXMLType(VARIANT * pvar,
  2007. LPCWSTR pcszDataTypeString)
  2008. {
  2009. HRESULT hr = S_OK;
  2010. VARTYPE vt = VT_ERROR;
  2011. VARIANT var;
  2012. VariantInit(&var);
  2013. vt = GetVarTypeFromString(pcszDataTypeString);
  2014. if (VT_EMPTY != vt)
  2015. {
  2016. var.vt = vt;
  2017. switch (vt)
  2018. {
  2019. case VT_I1:
  2020. case VT_I2:
  2021. case VT_I4:
  2022. case VT_R4:
  2023. case VT_R8:
  2024. case VT_UI1:
  2025. case VT_UI2:
  2026. case VT_UI4:
  2027. case VT_INT:
  2028. case VT_UINT:
  2029. case VT_CY:
  2030. case VT_BOOL:
  2031. case VT_DATE:
  2032. var.dblVal = 0;
  2033. break;
  2034. case VT_BSTR:
  2035. var.bstrVal = SysAllocString(L"");
  2036. if (NULL == var.bstrVal)
  2037. {
  2038. hr = E_OUTOFMEMORY;
  2039. }
  2040. break;
  2041. default:
  2042. hr = E_INVALIDARG;
  2043. }
  2044. }
  2045. else
  2046. {
  2047. // Should never happen because the data type strings come from
  2048. // our internal tables, which must be valid.
  2049. AssertSz(FALSE,
  2050. "CUPnPAutomationProxy::HrVariantInitForXMLType(): "
  2051. "Invalid data type string passed in");
  2052. }
  2053. if (SUCCEEDED(hr))
  2054. {
  2055. *pvar = var;
  2056. }
  2057. else
  2058. {
  2059. VariantClear(&var);
  2060. }
  2061. TraceError("CUPnPAutomationProxy::HrVariantInitFroXMLType(): "
  2062. "Exiting",
  2063. hr);
  2064. return hr;
  2065. }
  2066. HRESULT
  2067. CUPnPAutomationProxy::HrInvokeAction(
  2068. UPNP_CONTROL_REQUEST * pucreq,
  2069. UPNP_CONTROL_RESPONSE * pucresp)
  2070. {
  2071. HRESULT hr = S_OK;
  2072. UPNP_CONTROL_RESPONSE ucresp = {0};
  2073. UPNP_ACTION * pua = NULL;
  2074. pua = LookupActionByName(pucreq->bstrActionName);
  2075. if (pua)
  2076. {
  2077. // Check that we've got the right number of input arguments.
  2078. if (pua->cInArgs == pucreq->cInputArgs)
  2079. {
  2080. DWORD cTotalArgs = 0;
  2081. DWORD cOutArgs = 0;
  2082. VARIANTARG * rgvarg = NULL;
  2083. VARIANTARG * rgvargData = NULL;
  2084. VARIANT varResult;
  2085. EXCEPINFO excepInfo = {0};
  2086. VariantInit(&varResult);
  2087. // Build an array of arguments to pass to the service object.
  2088. cTotalArgs = pua->cInArgs + pua->cOutArgs;
  2089. if (pua->puaRetVal)
  2090. {
  2091. Assert(cTotalArgs > 0);
  2092. // In UTL, the retval is considered an out parameter. In the
  2093. // automation world, it's considered separate, so reduce the
  2094. // count of parameters by 1 if there is a retval.
  2095. cTotalArgs--;
  2096. }
  2097. cOutArgs = cTotalArgs - pua->cInArgs;
  2098. if (cTotalArgs > 0)
  2099. {
  2100. rgvarg = new VARIANTARG[cTotalArgs];
  2101. if (cOutArgs > 0)
  2102. {
  2103. rgvargData = new VARIANTARG[cOutArgs];
  2104. }
  2105. else
  2106. {
  2107. rgvargData = NULL;
  2108. }
  2109. if (rgvarg && (!cOutArgs || rgvargData))
  2110. {
  2111. // Have to copy the arguments in reverse order. Out args
  2112. // go first.
  2113. for (DWORD i = 0,
  2114. index = pua->cOutArgs - 1;
  2115. SUCCEEDED(hr) && (i < cOutArgs);
  2116. i++, index--)
  2117. {
  2118. UPNP_STATE_VARIABLE * pusvRelated = NULL;
  2119. pusvRelated = pua->rgOutArgs[index].pusvRelated;
  2120. hr = HrVariantInitForXMLType(&rgvargData[i],
  2121. pusvRelated->bstrDataType);
  2122. if (SUCCEEDED(hr))
  2123. {
  2124. rgvarg[i].vt = rgvargData[i].vt | VT_BYREF;
  2125. rgvarg[i].pdblVal = &(rgvargData[i].dblVal);
  2126. if (SUCCEEDED(hr))
  2127. {
  2128. TraceTag(ttidAutomationProxy,
  2129. "CUPnPAutomationProxy::HrInvokeAction(): "
  2130. "Successfully initialized output arg %d",
  2131. i);
  2132. }
  2133. else
  2134. {
  2135. TraceError("CUPnPAutomationProxy::HrInvokeAction(): "
  2136. "Failed to initialize output argument",
  2137. hr);
  2138. }
  2139. }
  2140. else
  2141. {
  2142. TraceError("CUPnPAutomationProxy::HrInvokeAction(): "
  2143. "Failed to initialize for XML data type",
  2144. hr);
  2145. }
  2146. }
  2147. if (SUCCEEDED(hr))
  2148. {
  2149. // Now the in arguments.
  2150. // i is the index into the array of arguments we'll
  2151. // pass to IDispatch::Invoke. It starts at the first
  2152. // index after the out arguments. j is the index into
  2153. // the array of input arguments - it starts at the last
  2154. // and goes down to the first.
  2155. for (DWORD i = cOutArgs, j = pucreq->cInputArgs - 1;
  2156. i < cTotalArgs;
  2157. i++, j--)
  2158. {
  2159. // These will only be read,
  2160. // so we're going to just do straight binary copies i.e.
  2161. // we won't do VariantCopy().
  2162. // Note that because of this, we don't own the memory used
  2163. // by the input argument elements, so we don't free them
  2164. // when we clean up rgvarg down below.
  2165. rgvarg[i] = pucreq->rgvarInputArgs[j];
  2166. }
  2167. }
  2168. }
  2169. else
  2170. {
  2171. hr = E_OUTOFMEMORY;
  2172. TraceError("CUPnPAutomationProxy::HrInvokeAction(): "
  2173. "Failed to allocate arguments array",
  2174. hr);
  2175. }
  2176. }
  2177. else
  2178. {
  2179. rgvarg = NULL;
  2180. }
  2181. // Now we have the arguments sorted out. Execute the request.
  2182. if (SUCCEEDED(hr))
  2183. {
  2184. DISPPARAMS actionParams;
  2185. actionParams.rgvarg = rgvarg;
  2186. actionParams.cArgs = cTotalArgs;
  2187. actionParams.rgdispidNamedArgs = NULL;
  2188. actionParams.cNamedArgs = 0;
  2189. hr = m_pdispService->Invoke(pua->dispid,
  2190. IID_NULL,
  2191. LOCALE_SYSTEM_DEFAULT,
  2192. DISPATCH_METHOD,
  2193. &actionParams,
  2194. &varResult,
  2195. &excepInfo,
  2196. NULL);
  2197. }
  2198. // Build a response.
  2199. if (SUCCEEDED(hr))
  2200. {
  2201. UPNP_CONTROL_RESPONSE_DATA * pucrd = NULL;
  2202. TraceTag(ttidAutomationProxy,
  2203. "CUPnPAutomationProxy::HrInvokeAction(): "
  2204. "Action %S executed successfully",
  2205. pua->bstrName);
  2206. ucresp.bstrActionName = SysAllocString(pua->bstrName);
  2207. if (ucresp.bstrActionName)
  2208. {
  2209. ucresp.fSucceeded = TRUE;
  2210. pucrd = &ucresp.ucrData;
  2211. if (pua->cOutArgs > 0)
  2212. {
  2213. pucrd->Success.rgvarOutputArgs = (VARIANT *) CoTaskMemAlloc(
  2214. pua->cOutArgs * sizeof(VARIANT));
  2215. if (pucrd->Success.rgvarOutputArgs)
  2216. {
  2217. DWORD dwStartIndex = 0;
  2218. pucrd->Success.cOutputArgs = pua->cOutArgs;
  2219. if (pua->puaRetVal)
  2220. {
  2221. VariantInit(&pucrd->Success.rgvarOutputArgs[0]);
  2222. hr = VariantCopy(&pucrd->Success.rgvarOutputArgs[0],
  2223. &varResult);
  2224. if (SUCCEEDED(hr))
  2225. {
  2226. dwStartIndex = 1;
  2227. TraceTag(ttidAutomationProxy,
  2228. "CUPnPAutomationProxy::"
  2229. "HrInvokeAction(): "
  2230. "Successfully copied retval");
  2231. }
  2232. else
  2233. {
  2234. TraceError("CUPnPAutomationProxy::"
  2235. "HrInvokeAction(): "
  2236. "Failed to copy retval",
  2237. hr);
  2238. }
  2239. }
  2240. if (SUCCEEDED(hr))
  2241. {
  2242. for (DWORD i = 0,
  2243. j = cOutArgs + dwStartIndex - 1;
  2244. SUCCEEDED(hr) && (i < cOutArgs);
  2245. i++, j--)
  2246. {
  2247. VariantInit(&pucrd->Success.rgvarOutputArgs[j]);
  2248. hr = VariantCopy(&pucrd->Success.rgvarOutputArgs[j],
  2249. &rgvargData[i]);
  2250. if (SUCCEEDED(hr))
  2251. {
  2252. TraceTag(ttidAutomationProxy,
  2253. "CUPnPAutomationProxy::"
  2254. "HrInvokeAction(): "
  2255. "Successfully copied out arg %d",
  2256. j);
  2257. }
  2258. else
  2259. {
  2260. TraceError("CUPnPAutomationProxy::"
  2261. "HrInvokeAction(): "
  2262. "Failed to copy out arg",
  2263. hr);
  2264. }
  2265. }
  2266. }
  2267. }
  2268. else
  2269. {
  2270. hr = E_OUTOFMEMORY;
  2271. TraceError("CUPnPAutomationProxy::HrInvokeAction(): "
  2272. "Failed to allocate memory for out args",
  2273. hr);
  2274. }
  2275. }
  2276. else
  2277. {
  2278. pucrd->Success.rgvarOutputArgs = NULL;
  2279. pucrd->Success.cOutputArgs = 0;
  2280. }
  2281. }
  2282. else
  2283. {
  2284. hr = E_OUTOFMEMORY;
  2285. TraceError("CUPnPAutomationProxy::HrInvokeAction(): "
  2286. "Failed to allocate memory for action name",
  2287. hr);
  2288. }
  2289. }
  2290. else if (DISP_E_EXCEPTION == hr)
  2291. {
  2292. UPNP_CONTROL_RESPONSE_DATA * pucrd = NULL;
  2293. TraceTag(ttidAutomationProxy,
  2294. "CUPnPAutomationProxy::HrInvokeAction(): "
  2295. "Action %S returned an exception",
  2296. pua->bstrName);
  2297. // Fix up the HRESULT. Even though this is an error in the
  2298. // UPnP sense, we are returning success because from the
  2299. // processing point of view, the request went through correctly
  2300. // and just returned a fault response.
  2301. hr = S_OK;
  2302. ucresp.bstrActionName = SysAllocString(pua->bstrName);
  2303. if (ucresp.bstrActionName)
  2304. {
  2305. ucresp.fSucceeded = FALSE;
  2306. pucrd = &ucresp.ucrData;
  2307. // If the service object requested deferred fill-in of
  2308. // the exception info, call its callback function now.
  2309. if (excepInfo.pfnDeferredFillIn)
  2310. {
  2311. hr = (*(excepInfo.pfnDeferredFillIn))(&excepInfo);
  2312. if (SUCCEEDED(hr))
  2313. {
  2314. TraceTag(ttidAutomationProxy,
  2315. "CUPnPAutomationProxy::HrInvokeAction(): "
  2316. "Successfully filled in "
  2317. "deferred exception info");
  2318. }
  2319. else
  2320. {
  2321. TraceError("CUPnPAutomationProxy::HrInvokeAction(): "
  2322. "Failed to fill in "
  2323. "deferred exception info",
  2324. hr);
  2325. }
  2326. }
  2327. if (SUCCEEDED(hr))
  2328. {
  2329. // excepInfo may not be complete
  2330. LPCWSTR pszSource = excepInfo.bstrSource ? excepInfo.bstrSource : L"501";
  2331. LPCWSTR pszDesc = excepInfo.bstrDescription ? excepInfo.bstrDescription : L"Action Failed";
  2332. hr = HrBuildFaultResponse(pucrd,
  2333. L"SOAP-ENV:Client",
  2334. L"UPnPError",
  2335. pszSource,
  2336. pszDesc);
  2337. }
  2338. }
  2339. else
  2340. {
  2341. hr = E_OUTOFMEMORY;
  2342. TraceError("CUPnPAutomationProxy::HrInvokeAction(): "
  2343. "Failed to allocate memory for action name",
  2344. hr);
  2345. }
  2346. }
  2347. else
  2348. {
  2349. TraceError("CUPnPAutomationProxy::HrInvokeAction(): "
  2350. "Failed to invoke action",
  2351. hr);
  2352. // Build up a SOAP Fault response with the UPnP error code
  2353. // "501 - Action Failed". Allow the above HRESULT to be lost
  2354. // because even though there was an "error", we're going to
  2355. // return success.
  2356. ucresp.bstrActionName = SysAllocString(pua->bstrName);
  2357. if (ucresp.bstrActionName)
  2358. {
  2359. UPNP_CONTROL_RESPONSE_DATA * pucrd = NULL;
  2360. ucresp.fSucceeded = FALSE;
  2361. pucrd = &ucresp.ucrData;
  2362. hr = HrBuildFaultResponse(pucrd,
  2363. L"SOAP-ENV:Client",
  2364. L"UPnPError",
  2365. L"501",
  2366. L"Action Failed");
  2367. }
  2368. else
  2369. {
  2370. hr = E_OUTOFMEMORY;
  2371. TraceError("CUPnPAutomationProxy::HrInvokeAction(): "
  2372. "Failed to allocate memory for action name",
  2373. hr);
  2374. }
  2375. }
  2376. // Cleanup. At this point, all the output information should be
  2377. // in the ucresp structure.
  2378. if (rgvarg)
  2379. {
  2380. // The input arguments were straight binary copies, so
  2381. // we don't want to free them. Free only the output arguments.
  2382. for (DWORD i = 0; i < cOutArgs; i++)
  2383. {
  2384. VariantClear(&rgvargData[i]);
  2385. }
  2386. delete [] rgvarg;
  2387. delete [] rgvargData;
  2388. rgvarg = NULL;
  2389. rgvargData = NULL;
  2390. cTotalArgs = 0;
  2391. }
  2392. VariantClear(&varResult);
  2393. }
  2394. else
  2395. {
  2396. // Invalid arguments.
  2397. ucresp.fSucceeded = FALSE;
  2398. hr = HrBuildFaultResponse(&ucresp.ucrData,
  2399. L"SOAP-ENV:Client",
  2400. L"UPnPError",
  2401. L"402",
  2402. L"Invalid Args");
  2403. }
  2404. }
  2405. else
  2406. {
  2407. // Invalid Action name
  2408. ucresp.fSucceeded = FALSE;
  2409. hr = HrBuildFaultResponse(&ucresp.ucrData,
  2410. L"SOAP-ENV:Client",
  2411. L"UPnPError",
  2412. L"401",
  2413. L"Invalid Action");
  2414. }
  2415. // If succeeded, copy the response info to the output structure, otherwise
  2416. // free it.
  2417. if (SUCCEEDED(hr))
  2418. {
  2419. *pucresp = ucresp;
  2420. }
  2421. else
  2422. {
  2423. FreeControlResponse(&ucresp);
  2424. }
  2425. TraceError("CUPnPAutomationProxy::HrInvokeAction(): "
  2426. "Exiting",
  2427. hr);
  2428. return hr;
  2429. }
  2430. HRESULT
  2431. CUPnPAutomationProxy::HrQueryStateVariable(
  2432. UPNP_CONTROL_REQUEST * pucreq,
  2433. UPNP_CONTROL_RESPONSE * pucresp)
  2434. {
  2435. HRESULT hr = S_OK;
  2436. UPNP_CONTROL_RESPONSE ucresp = {0};
  2437. UPNP_STATE_VARIABLE * pusv = NULL;
  2438. BSTR bstrVarName = NULL;
  2439. // QueryStateVariable should have 1 input argument which is the variable
  2440. // name.
  2441. Assert(pucreq->cInputArgs == 1);
  2442. Assert(pucreq->rgvarInputArgs[0].vt == VT_BSTR);
  2443. bstrVarName = V_BSTR(&pucreq->rgvarInputArgs[0]);
  2444. pusv = LookupVariableByName(bstrVarName);
  2445. if (pusv)
  2446. {
  2447. DISPPARAMS dispparamsEmpty = {NULL, NULL, 0, 0};
  2448. VARIANT varResult;
  2449. EXCEPINFO excepInfo = {0};
  2450. VariantInit(&varResult);
  2451. // Query the value.
  2452. hr = m_pdispService->Invoke(pusv->dispid,
  2453. IID_NULL,
  2454. LOCALE_SYSTEM_DEFAULT,
  2455. DISPATCH_PROPERTYGET,
  2456. &dispparamsEmpty,
  2457. &varResult,
  2458. &excepInfo,
  2459. NULL);
  2460. // Build a response.
  2461. if (SUCCEEDED(hr))
  2462. {
  2463. UPNP_CONTROL_RESPONSE_DATA * pucrd = NULL;
  2464. TraceTag(ttidAutomationProxy,
  2465. "CUPnPAutomationProxy::HrQueryStateVariable(): "
  2466. "PROPGET for %S succeeded",
  2467. bstrVarName);
  2468. ucresp.bstrActionName = SysAllocString(L"QueryStateVariable");
  2469. if (ucresp.bstrActionName)
  2470. {
  2471. ucresp.fSucceeded = TRUE;
  2472. pucrd = &ucresp.ucrData;
  2473. pucrd->Success.cOutputArgs = 1;
  2474. pucrd->Success.rgvarOutputArgs = (VARIANT *) CoTaskMemAlloc(
  2475. sizeof(VARIANT));
  2476. if (pucrd->Success.rgvarOutputArgs)
  2477. {
  2478. VariantInit(&pucrd->Success.rgvarOutputArgs[0]);
  2479. hr = VariantCopy(&pucrd->Success.rgvarOutputArgs[0],
  2480. &varResult);
  2481. if (SUCCEEDED(hr))
  2482. {
  2483. TraceTag(ttidAutomationProxy,
  2484. "CUPnPAutomationProxy::HrQueryStateVariable(): "
  2485. "Successfully copied result to output");
  2486. }
  2487. else
  2488. {
  2489. TraceError("CUPnPAutomationProxy::HrQueryStateVariable(): "
  2490. "Failed to copy result to output",
  2491. hr);
  2492. }
  2493. }
  2494. else
  2495. {
  2496. hr = E_OUTOFMEMORY;
  2497. TraceError("CUPnPAutomationProxy::HrQueryStateVariable(): "
  2498. "Failed to allocate memory for output arg",
  2499. hr);
  2500. }
  2501. }
  2502. else
  2503. {
  2504. hr = E_OUTOFMEMORY;
  2505. TraceError("CUPnPAutomationProxy::HrQueryStateVariable(): "
  2506. "Failed to allocate memory for action name",
  2507. hr);
  2508. }
  2509. }
  2510. else if (DISP_E_EXCEPTION == hr)
  2511. {
  2512. UPNP_CONTROL_RESPONSE_DATA * pucrd = NULL;
  2513. TraceTag(ttidAutomationProxy,
  2514. "CUPnPAutomationProxy::HrQueryStateVariable(): "
  2515. "PROPGET for %S returned an exception",
  2516. bstrVarName);
  2517. // Fix up the HRESULT. Even though this is an error in the
  2518. // UPnP sense, we are returning success because from the
  2519. // processing point of view, the request went through correctly
  2520. // and just returned a fault response.
  2521. hr = S_OK;
  2522. ucresp.bstrActionName = SysAllocString(L"QueryStateVariable");
  2523. if (ucresp.bstrActionName)
  2524. {
  2525. ucresp.fSucceeded = FALSE;
  2526. pucrd = &ucresp.ucrData;
  2527. // If the service object requested deferred fill-in of
  2528. // the exception info, call its callback function now.
  2529. if (excepInfo.pfnDeferredFillIn)
  2530. {
  2531. hr = (*(excepInfo.pfnDeferredFillIn))(&excepInfo);
  2532. if (SUCCEEDED(hr))
  2533. {
  2534. TraceTag(ttidAutomationProxy,
  2535. "CUPnPAutomationProxy::HrQueryStateVariable(): "
  2536. "Successfully filled in "
  2537. "deferred exception info");
  2538. }
  2539. else
  2540. {
  2541. TraceError("CUPnPAutomationProxy::HrQueryStateVariable(): "
  2542. "Failed to fill in "
  2543. "deferred exception info",
  2544. hr);
  2545. }
  2546. }
  2547. if (SUCCEEDED(hr))
  2548. {
  2549. // excepInfo may not be complete
  2550. LPCWSTR pszSource = excepInfo.bstrSource ? excepInfo.bstrSource : L"501";
  2551. LPCWSTR pszDesc = excepInfo.bstrDescription ? excepInfo.bstrDescription : L"Action Failed";
  2552. hr = HrBuildFaultResponse(pucrd,
  2553. L"SOAP-ENV:Client",
  2554. L"UPnPError",
  2555. pszSource,
  2556. pszDesc);
  2557. }
  2558. }
  2559. else
  2560. {
  2561. hr = E_OUTOFMEMORY;
  2562. TraceError("CUPnPAutomationProxy::HrQueryStateVariable(): "
  2563. "Failed to allocate memory for action name",
  2564. hr);
  2565. }
  2566. }
  2567. else
  2568. {
  2569. TraceError("CUPnPAutomationProxy::HrQueryStateVariable(): "
  2570. "PROPGET failed",
  2571. hr);
  2572. }
  2573. VariantClear(&varResult);
  2574. }
  2575. else
  2576. {
  2577. // Invalid variable name
  2578. ucresp.fSucceeded = FALSE;
  2579. hr = HrBuildFaultResponse(&ucresp.ucrData,
  2580. L"SOAP-ENV:Client",
  2581. L"UPnPError",
  2582. L"404",
  2583. L"Invalid Var");
  2584. }
  2585. // If succeeded, copy the response info to the output structure, otherwise
  2586. // free it.
  2587. if (SUCCEEDED(hr))
  2588. {
  2589. *pucresp = ucresp;
  2590. }
  2591. else
  2592. {
  2593. FreeControlResponse(&ucresp);
  2594. }
  2595. TraceError("CUPnPAutomationProxy::HrQueryStateVariable(): "
  2596. "Exiting",
  2597. hr);
  2598. return hr;
  2599. }