Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1585 lines
33 KiB

  1. // scecore.h: interface for the core services sceprov provides.
  2. // Copyright (c)1997-2001 Microsoft Corporation
  3. //
  4. //////////////////////////////////////////////////////////////////////
  5. #include "precomp.h"
  6. #include "sceprov.h"
  7. #include "sceparser.h"
  8. // IScePathParser
  9. /*
  10. Routine Description:
  11. Name:
  12. CScePathParser::CScePathParser
  13. Functionality:
  14. Constructor. Initialize pointer members.
  15. Virtual:
  16. No.
  17. Arguments:
  18. None.
  19. Return Value:
  20. None.
  21. Notes:
  22. If you add more members, please initialize them here.
  23. */
  24. CScePathParser::CScePathParser ()
  25. :
  26. m_pszNamespace(NULL),
  27. m_pszClassName(NULL)
  28. {
  29. }
  30. /*
  31. Routine Description:
  32. Name:
  33. CScePathParser::~CScePathParser
  34. Functionality:
  35. Destructor. Do clean up (free memory).
  36. Virtual:
  37. No.
  38. Arguments:
  39. None.
  40. Return Value:
  41. None.
  42. Notes:
  43. If you add more members, please consider do clean up in the Cleanup function.
  44. */
  45. CScePathParser::~CScePathParser()
  46. {
  47. Cleanup();
  48. }
  49. /*
  50. Routine Description:
  51. Name:
  52. CScePathParser::ParsePath
  53. Functionality:
  54. Parsing given path and store results in our members.
  55. Virtual:
  56. Yes.
  57. Arguments:
  58. pszObjectPath - the path to be parsed.
  59. Return Value:
  60. Success: S_OK
  61. Failure: various error code. Any such error indicates the failure to parse the path.
  62. (1) E_INVALIDARG
  63. (2) E_OUTOFMEMORY
  64. (3) E_UNEXPECTED for syntax error
  65. Notes:
  66. (1) Since this is regular COM server interface function, we use regular COM errors
  67. instead of WMI errors. However, we can't guarantee what WMI returns.
  68. */
  69. STDMETHODIMP
  70. CScePathParser::ParsePath (
  71. IN LPCWSTR pszObjectPath
  72. )
  73. {
  74. if (pszObjectPath == NULL || *pszObjectPath == L'\0')
  75. {
  76. return E_INVALIDARG;
  77. }
  78. //
  79. // just in case, this object has already parsed before. This allows repeated use of the same
  80. // CScePathParser for parsing different paths.
  81. //
  82. Cleanup();
  83. //
  84. // Ask WMI for their path parser
  85. //
  86. CComPtr<IWbemPath> srpPathParser;
  87. HRESULT hr = ::GetWbemPathParser(&srpPathParser);
  88. if (FAILED(hr))
  89. {
  90. return hr;
  91. }
  92. //
  93. // This is the parsing function.
  94. //
  95. hr = srpPathParser->SetText(WBEMPATH_CREATE_ACCEPT_ALL | WBEMPATH_TREAT_SINGLE_IDENT_AS_NS, pszObjectPath);
  96. if (FAILED(hr))
  97. {
  98. return hr;
  99. }
  100. //
  101. // Get the results...
  102. //
  103. ULONG uBufSize = 0;
  104. DWORD dwCount = 0;
  105. //
  106. // get namespace count
  107. //
  108. hr = srpPathParser->GetNamespaceCount(&dwCount);
  109. if (dwCount > 0)
  110. {
  111. //
  112. // get the length needed for the namespace
  113. //
  114. hr = srpPathParser->GetNamespaceAt(0, &uBufSize, NULL);
  115. if (FAILED(hr))
  116. {
  117. return hr;
  118. }
  119. //
  120. // we will free this memory.
  121. //
  122. m_pszNamespace = new WCHAR[uBufSize];
  123. if (m_pszNamespace == NULL)
  124. {
  125. return E_OUTOFMEMORY;
  126. }
  127. //
  128. // will ignore the result
  129. //
  130. hr = srpPathParser->GetNamespaceAt(0, &uBufSize, m_pszNamespace);
  131. }
  132. //
  133. // get the buffer size needed for the class name
  134. //
  135. uBufSize = 0;
  136. hr = srpPathParser->GetClassName(&uBufSize, NULL);
  137. if (SUCCEEDED(hr))
  138. {
  139. //
  140. // we will free this memory.
  141. //
  142. m_pszClassName = new WCHAR[uBufSize];
  143. if (m_pszClassName == NULL)
  144. {
  145. return E_OUTOFMEMORY;
  146. }
  147. //
  148. // WMI path parser don't have a documented behavior as when the class name
  149. // will be missing.
  150. //
  151. hr = srpPathParser->GetClassName(&uBufSize, m_pszClassName);
  152. }
  153. else
  154. {
  155. //
  156. // this clearly don't have a class name, then the namespace should be the class name.
  157. // for some reason, Query parser doesn't give us class name in case of singleton
  158. // and the class name ends up in the namespace member. Obviously, in this case, there is no
  159. // key properties.
  160. //
  161. //
  162. // must have a namespace
  163. //
  164. if (m_pszNamespace)
  165. {
  166. //
  167. // prepare to switch m_pszClassName to point to what the namesapce does.
  168. //
  169. delete [] m_pszClassName;
  170. m_pszClassName = m_pszNamespace;
  171. m_pszNamespace = NULL;
  172. //
  173. // we can return because there is no key property
  174. //
  175. return S_OK;
  176. }
  177. else
  178. {
  179. hr = E_UNEXPECTED;
  180. }
  181. }
  182. if (FAILED(hr))
  183. {
  184. return hr;
  185. }
  186. //
  187. // get key properties
  188. //
  189. CComPtr<IWbemPathKeyList> srpKeyList;
  190. hr = srpPathParser->GetKeyList(&srpKeyList);
  191. if (FAILED(hr))
  192. {
  193. return hr;
  194. }
  195. //
  196. // now get the Key and value pairs
  197. //
  198. ULONG uKeyCount = 0;
  199. hr = srpKeyList->GetCount(&uKeyCount);
  200. if (FAILED(hr) || uKeyCount == 0)
  201. {
  202. return hr;
  203. }
  204. for (ULONG i = 0; i < uKeyCount; i++)
  205. {
  206. //
  207. // this pKeyVal will cache the (name, value) pair
  208. //
  209. CPropValuePair* pKeyVal = NULL;
  210. uBufSize = 0;
  211. //
  212. // now get the size of buffer needed
  213. //
  214. CComVariant var;
  215. ULONG uCimType = CIM_EMPTY;
  216. hr = srpKeyList->GetKey2(i,
  217. 0,
  218. &uBufSize,
  219. NULL,
  220. &var,
  221. &uCimType);
  222. if (SUCCEEDED(hr))
  223. {
  224. //
  225. // our vector will manage the memory used by pKeyVal
  226. //
  227. pKeyVal = new CPropValuePair;
  228. if (pKeyVal == NULL)
  229. {
  230. hr = E_OUTOFMEMORY;
  231. break;
  232. }
  233. //
  234. // need the name buffer
  235. //
  236. pKeyVal->pszKey = new WCHAR[uBufSize];
  237. //
  238. // variant member of pKeyVal needs to be initialized as well.
  239. //
  240. ::VariantInit(&(pKeyVal->varVal));
  241. //
  242. // secondary allocation fails, need to free the first level pointer
  243. //
  244. if (pKeyVal->pszKey == NULL)
  245. {
  246. delete pKeyVal;
  247. pKeyVal = NULL;
  248. hr = E_OUTOFMEMORY;
  249. break;
  250. }
  251. }
  252. if (SUCCEEDED(hr))
  253. {
  254. hr = srpKeyList->GetKey2(i,
  255. 0,
  256. &uBufSize,
  257. pKeyVal->pszKey,
  258. &(pKeyVal->varVal),
  259. &uCimType);
  260. }
  261. if (SUCCEEDED(hr))
  262. {
  263. m_vecKeyValueList.push_back(pKeyVal);
  264. }
  265. else
  266. {
  267. //
  268. // for any failure, we need to free the resource already partially allocated
  269. // for the pKeyVal. This pKeyVal is pointing to our class, which knows how to free its members,
  270. // this delete is enough.
  271. //
  272. delete pKeyVal;
  273. break;
  274. }
  275. }
  276. if (SUCCEEDED(hr))
  277. {
  278. hr = S_OK;
  279. }
  280. return hr;
  281. }
  282. /*
  283. Routine Description:
  284. Name:
  285. CScePathParser::GetKeyPropertyCount
  286. Functionality:
  287. Get the key proeprty count contained in the path.
  288. Virtual:
  289. Yes.
  290. Arguments:
  291. pCount - receives the count.
  292. Return Value:
  293. Success: S_OK
  294. Failure: E_INVALIDARG.
  295. Notes:
  296. (1) Since this is regular COM server interface function, we use regular COM errors
  297. instead of WMI errors. However, we can't guarantee what WMI returns.
  298. */
  299. STDMETHODIMP
  300. CScePathParser::GetKeyPropertyCount (
  301. OUT DWORD *pCount
  302. )
  303. {
  304. if (pCount == NULL)
  305. {
  306. return E_INVALIDARG;
  307. }
  308. *pCount = m_vecKeyValueList.size();
  309. return S_OK;
  310. }
  311. /*
  312. Routine Description:
  313. Name:
  314. CScePathParser::GetNamespace
  315. Functionality:
  316. Get the namespace.
  317. Virtual:
  318. Yes.
  319. Arguments:
  320. pbstrNamespace - receives the namespace string.
  321. Return Value:
  322. Success: S_OK
  323. Failure:
  324. (1) E_INVALIDARG
  325. (2) E_OUTOFMEMORY
  326. (3) E_UNEXPECTED for syntax error
  327. Notes:
  328. (1) Since this is regular COM server interface function, we use regular COM errors
  329. instead of WMI errors. However, we can't guarantee what WMI returns.
  330. */
  331. STDMETHODIMP
  332. CScePathParser::GetNamespace (
  333. OUT BSTR *pbstrNamespace
  334. )
  335. {
  336. if (pbstrNamespace == NULL)
  337. {
  338. return E_INVALIDARG;
  339. }
  340. if (m_pszNamespace)
  341. {
  342. *pbstrNamespace = ::SysAllocString(m_pszNamespace);
  343. }
  344. else
  345. {
  346. return E_UNEXPECTED;
  347. }
  348. return (*pbstrNamespace) ? S_OK : E_OUTOFMEMORY;
  349. }
  350. /*
  351. Routine Description:
  352. Name:
  353. CScePathParser::GetClassName
  354. Functionality:
  355. Get the class name.
  356. Virtual:
  357. Yes.
  358. Arguments:
  359. pbstrClassName - receives the class name string.
  360. Return Value:
  361. Success: S_OK
  362. Failure:
  363. (1) E_INVALIDARG
  364. (2) E_OUTOFMEMORY
  365. (3) E_UNEXPECTED for syntax error
  366. Notes:
  367. (1) Since this is regular COM server interface function, we use regular COM errors
  368. instead of WMI errors. However, we can't guarantee what WMI returns.
  369. */
  370. STDMETHODIMP
  371. CScePathParser::GetClassName (
  372. OUT BSTR *pbstrClassName
  373. )
  374. {
  375. if (pbstrClassName == NULL)
  376. {
  377. return E_INVALIDARG;
  378. }
  379. if (m_pszClassName)
  380. {
  381. *pbstrClassName = ::SysAllocString(m_pszClassName);
  382. }
  383. else
  384. {
  385. return E_UNEXPECTED;
  386. }
  387. return (*pbstrClassName) ? S_OK : E_OUTOFMEMORY;
  388. }
  389. /*
  390. Routine Description:
  391. Name:
  392. CScePathParser::GetKeyPropertyValue
  393. Functionality:
  394. Get the named property's value
  395. Virtual:
  396. Yes.
  397. Arguments:
  398. pszKeyPropName - The key property's name whose value is to be retrieved.
  399. pvarValue - receives the value.
  400. Return Value:
  401. Success: S_OK if the property value is properly retrieved.
  402. WBEM_S_FALSE if the property value can't be found.
  403. Failure:
  404. (1) E_INVALIDARG
  405. (2) E_OUTOFMEMORY
  406. (5) Or errors from VariantCopy
  407. Notes:
  408. (1) Since this is regular COM server interface function, we use regular COM errors
  409. instead of WMI errors. However, we can't guarantee what WMI returns.
  410. */
  411. STDMETHODIMP
  412. CScePathParser::GetKeyPropertyValue (
  413. IN LPCWSTR pszKeyPropName,
  414. OUT VARIANT *pvarValue
  415. )
  416. {
  417. if (pszKeyPropName == NULL || *pszKeyPropName == L'\0' || pvarValue == NULL)
  418. {
  419. return E_INVALIDARG;
  420. }
  421. //
  422. // set the variant to a valid empty initial state
  423. //
  424. ::VariantInit(pvarValue);
  425. //
  426. // assume we can't find the property
  427. //
  428. HRESULT hr = WBEM_S_FALSE;
  429. std::vector<CPropValuePair*>::iterator it;
  430. //
  431. // find the property (case-insensitive name comparison) and copy the value
  432. //
  433. for (it = m_vecKeyValueList.begin(); it != m_vecKeyValueList.end(); it++)
  434. {
  435. if (_wcsicmp((*it)->pszKey, pszKeyPropName) == 0)
  436. {
  437. hr = ::VariantCopy(pvarValue, &((*it)->varVal));
  438. break;
  439. }
  440. }
  441. return hr;
  442. }
  443. /*
  444. Routine Description:
  445. Name:
  446. CScePathParser::GetKeyPropertyValueByIndex
  447. Functionality:
  448. Get the indexed property name and value.
  449. Virtual:
  450. Yes.
  451. Arguments:
  452. dwIndex - the (name, value) pair's index.
  453. pbstrKeyPropName - receives key property's name.
  454. pvarValue - receives the value. In caller not interested, this can be NULL.
  455. Return Value:
  456. Success: S_OK
  457. Failure:
  458. (1) E_INVALIDARG (illegal null or index out of range)
  459. (2) E_OUTOFMEMORY
  460. (3) E_UNEXPECTED for can't find the property
  461. (4) Or errors from VariantCopy
  462. Notes:
  463. (1) Since this is regular COM server interface function, we use regular COM errors
  464. instead of WMI errors. However, we can't guarantee what WMI returns.
  465. */
  466. STDMETHODIMP CScePathParser::GetKeyPropertyValueByIndex (
  467. IN DWORD dwIndex,
  468. OUT BSTR* pbstrKeyPropName,
  469. OUT VARIANT *pvarValue OPTIONAL
  470. )
  471. {
  472. if (dwIndex >= m_vecKeyValueList.size() || pbstrKeyPropName == NULL)
  473. {
  474. return E_INVALIDARG;
  475. }
  476. //
  477. // assume we can't find it
  478. //
  479. HRESULT hr = E_UNEXPECTED;
  480. //
  481. // initialize the out parameters
  482. //
  483. *pbstrKeyPropName = NULL;
  484. if (pvarValue)
  485. {
  486. ::VariantInit(pvarValue);
  487. }
  488. CPropValuePair *pKV = m_vecKeyValueList[dwIndex];
  489. if (pKV)
  490. {
  491. *pbstrKeyPropName = ::SysAllocString(pKV->pszKey);
  492. if (pbstrKeyPropName == NULL)
  493. {
  494. hr = E_OUTOFMEMORY;
  495. }
  496. if (SUCCEEDED(hr) && pvarValue)
  497. {
  498. hr = ::VariantCopy(pvarValue, &(pKV->varVal));
  499. //
  500. // don't want to return partial results
  501. //
  502. if (FAILED(hr))
  503. {
  504. ::SysFreeString(*pbstrKeyPropName);
  505. *pbstrKeyPropName = NULL;
  506. }
  507. }
  508. }
  509. return hr;
  510. }
  511. /*
  512. Routine Description:
  513. Name:
  514. CScePathParser::Cleanup
  515. Functionality:
  516. Free memory resources.
  517. Virtual:
  518. No.
  519. Arguments:
  520. None.
  521. Return Value:
  522. None.
  523. Notes:
  524. Consider adding your clean up code here should you need to add members.
  525. */
  526. void CScePathParser::Cleanup()
  527. {
  528. //
  529. // empty the vector. Since the vector manages the (name, value) pair,
  530. // its contents need to be deleted!
  531. //
  532. std::vector<CPropValuePair*>::iterator it;
  533. for (it = m_vecKeyValueList.begin(); it != m_vecKeyValueList.end(); ++it)
  534. {
  535. delete *it;
  536. }
  537. m_vecKeyValueList.empty();
  538. //
  539. // This function may be called not just inside the destructor,
  540. // so, properly reset the pointer values after free its memory.
  541. //
  542. delete [] m_pszNamespace;
  543. m_pszNamespace = NULL;
  544. delete [] m_pszClassName;
  545. m_pszClassName = NULL;
  546. }
  547. //================================================================================================
  548. // implementations for CSceQueryParser
  549. //================================================================================================
  550. /*
  551. Routine Description:
  552. Name:
  553. CSceQueryParser::CSceQueryParser
  554. Functionality:
  555. Constructor. All members are classes. They initialize automatically.
  556. Virtual:
  557. No.
  558. Arguments:
  559. None.
  560. Return Value:
  561. None.
  562. Notes:
  563. If you add more members, please initialize them here.
  564. */
  565. CSceQueryParser::CSceQueryParser()
  566. {
  567. }
  568. /*
  569. Routine Description:
  570. Name:
  571. CSceQueryParser::~CSceQueryParser
  572. Functionality:
  573. Destructor. do clean up.
  574. Virtual:
  575. No.
  576. Arguments:
  577. None.
  578. Return Value:
  579. None.
  580. Notes:
  581. If you add more members, please initialize them here.
  582. */
  583. CSceQueryParser::~CSceQueryParser()
  584. {
  585. Cleanup();
  586. }
  587. /*
  588. Routine Description:
  589. Name:
  590. CSceQueryParser::GetClassName
  591. Functionality:
  592. Get the class's name for the given index.
  593. Virtual:
  594. Yes.
  595. Arguments:
  596. iIndex - The index of the class. Currently, this is not used because WMI only
  597. support unary query - query that spans over one class. What we won't
  598. design our interface into that.
  599. pbstrClassName - Receives the class name.
  600. Return Value:
  601. Success: S_OK
  602. Failure:
  603. (1) E_INVALIDARG (illegal null or index out of range)
  604. (2) E_OUTOFMEMORY
  605. (3) E_UNEXPECTED for can't find the property
  606. (4) Or errors from VariantCopy
  607. Notes:
  608. (1) Since this is regular COM server interface function, we use regular COM errors
  609. instead of WMI errors. However, we can't guarantee what WMI returns.
  610. */
  611. STDMETHODIMP
  612. CSceQueryParser::GetClassName (
  613. IN int iIndex,
  614. OUT BSTR * pbstrClassName
  615. )
  616. {
  617. if (pbstrClassName == NULL || iIndex >= m_vecClassList.size())
  618. {
  619. return E_INVALIDARG;
  620. }
  621. if (m_vecClassList[iIndex])
  622. {
  623. *pbstrClassName = ::SysAllocString(m_vecClassList[iIndex]);
  624. }
  625. else
  626. {
  627. return E_UNEXPECTED;
  628. }
  629. return (*pbstrClassName) ? S_OK : E_OUTOFMEMORY;
  630. }
  631. /*
  632. Routine Description:
  633. Name:
  634. CSceQueryParser::GetGetQueryingPropertyValue
  635. Functionality:
  636. Get querying property's value given the index.
  637. Virtual:
  638. Yes.
  639. Arguments:
  640. iIndex - Since the same querying property may have multiple values in the where clause
  641. this is to get the iIndex-th value of the querying property. If you have a query
  642. like this:
  643. select * from Foo where FooVal = 1 AND BarVal = 5 OR FooVal = 2 AND BarVal = 6
  644. you will end up only with FooVal's. The reason for this limitation is that WMI
  645. doesn't have a full support on it (parser is maturing) and it's way too complicated
  646. for our SCE parser. For users who needs that kind of support, please use WMI's query
  647. parser directly.
  648. pbstrQPValue - Receives the querying property's value in string format.
  649. Return Value:
  650. Success: S_OK
  651. Failure:
  652. (1) E_INVALIDARG (illegal null or index out of range)
  653. (2) E_OUTOFMEMORY
  654. (3) E_UNEXPECTED for can't find the property
  655. Notes:
  656. (1) Since this is regular COM server interface function, we use regular COM errors
  657. instead of WMI errors. However, we can't guarantee what WMI returns.
  658. */
  659. STDMETHODIMP
  660. CSceQueryParser::GetQueryingPropertyValue (
  661. IN int iIndex,
  662. OUT BSTR * pbstrQPValue
  663. )
  664. {
  665. if (pbstrQPValue == NULL || iIndex >= m_vecQueryingPropValueList.size())
  666. {
  667. return E_INVALIDARG;
  668. }
  669. if (m_vecQueryingPropValueList[iIndex])
  670. {
  671. *pbstrQPValue = ::SysAllocString(m_vecQueryingPropValueList[iIndex]);
  672. }
  673. else
  674. {
  675. return E_UNEXPECTED;
  676. }
  677. return (*pbstrQPValue) ? S_OK : E_OUTOFMEMORY;
  678. }
  679. /*
  680. Routine Description:
  681. Name:
  682. CSceQueryParser::Cleanup
  683. Functionality:
  684. free the resources held by our members.
  685. Virtual:
  686. No.
  687. Arguments:
  688. None.
  689. Return Value:
  690. None.
  691. Notes:
  692. (1) Consider add clean up code here should you need to add more members.
  693. */
  694. void CSceQueryParser::Cleanup()
  695. {
  696. //
  697. // both vectors are storing heap strings, need to delete the contents!
  698. //
  699. std::vector<LPWSTR>::iterator it;
  700. for (it = m_vecClassList.begin(); it != m_vecClassList.end(); it++)
  701. {
  702. delete [] (*it);
  703. }
  704. m_vecClassList.empty();
  705. for (it = m_vecQueryingPropValueList.begin(); it != m_vecQueryingPropValueList.end(); it++)
  706. {
  707. delete [] (*it);
  708. }
  709. m_vecQueryingPropValueList.empty();
  710. m_bstrQueryingPropName.Empty();
  711. }
  712. /*
  713. Routine Description:
  714. Name:
  715. CSceQueryParser::ParseQuery
  716. Functionality:
  717. Given the property name we are looking for, this function will parsing the query.
  718. Virtual:
  719. Yes.
  720. Arguments:
  721. strQuery - The query to be parsed.
  722. strQueryPropName - The querying property (the property we are looking for in the query).
  723. Return Value:
  724. Success: S_OK
  725. Failure:
  726. (1) E_INVALIDARG (illegal null or index out of range)
  727. (2) E_OUTOFMEMORY
  728. (3) E_UNEXPECTED for can't find the property
  729. (4) Other errors from WMI query parser.
  730. Notes:
  731. (1) Since this is regular COM server interface function, we use regular COM errors
  732. instead of WMI errors. However, we can't guarantee what WMI returns.
  733. */
  734. STDMETHODIMP CSceQueryParser::ParseQuery (
  735. IN LPCWSTR strQuery,
  736. IN LPCWSTR strQueryPropName
  737. )
  738. {
  739. if (strQuery == NULL || *strQuery == L'\0')
  740. {
  741. return E_INVALIDARG;
  742. }
  743. CComPtr<IWbemQuery> srpQuery;
  744. //
  745. // Get the WMI query object
  746. //
  747. HRESULT hr = ::GetWbemQuery(&srpQuery);
  748. if (FAILED(hr))
  749. {
  750. return hr;
  751. }
  752. //
  753. // Set up the query parser to use
  754. //
  755. ULONG uFeatures[] = {WMIQ_LF1_BASIC_SELECT, WMIQ_LF2_CLASS_NAME_IN_QUERY};
  756. hr = srpQuery->SetLanguageFeatures(0, sizeof(uFeatures)/sizeof(*uFeatures), uFeatures);
  757. if (FAILED(hr))
  758. {
  759. return hr;
  760. }
  761. //
  762. // we are ready to parse, so, cleanup
  763. //
  764. Cleanup();
  765. //
  766. // parse the query
  767. //
  768. hr = srpQuery->Parse(L"WQL", strQuery, 0);
  769. if (FAILED(hr))
  770. {
  771. return hr;
  772. }
  773. //
  774. // Get the parsing results
  775. //
  776. //
  777. // need to free memory. Don't do it ourselves. Ask query to free it!
  778. //
  779. SWbemRpnEncodedQuery *pRpn = 0;
  780. hr = srpQuery->GetAnalysis(WMIQ_ANALYSIS_RPN_SEQUENCE, 0, (LPVOID *) &pRpn);
  781. if (SUCCEEDED(hr))
  782. {
  783. //
  784. // Need the class name from the results
  785. //
  786. hr = ExtractClassNames(pRpn);
  787. //
  788. // need the querying property values
  789. //
  790. if (SUCCEEDED(hr) && strQueryPropName && *strQueryPropName != L'\0')
  791. {
  792. m_bstrQueryingPropName = strQueryPropName;
  793. hr = ExtractQueryingProperties(pRpn, strQueryPropName);
  794. }
  795. srpQuery->FreeMemory(pRpn);
  796. }
  797. return SUCCEEDED(hr) ? S_OK : hr;
  798. }
  799. /*
  800. Routine Description:
  801. Name:
  802. CSceQueryParser::ExtractClassNames
  803. Functionality:
  804. Private helper to get the class name(s) from the query results.
  805. Virtual:
  806. No.
  807. Arguments:
  808. pRpn - The query result.
  809. Return Value:
  810. Success: S_OK
  811. Failure:
  812. (1) E_INVALIDARG (illegal null or index out of range)
  813. (2) E_OUTOFMEMORY.
  814. Notes:
  815. (1) Since this is regular COM server interface function, we use regular COM errors
  816. instead of WMI errors. However, we can't guarantee what WMI returns.
  817. */
  818. HRESULT CSceQueryParser::ExtractClassNames (
  819. SWbemRpnEncodedQuery *pRpn
  820. )
  821. {
  822. if (pRpn == NULL)
  823. {
  824. return E_INVALIDARG;
  825. }
  826. HRESULT hr = S_OK;
  827. int iLen = 0;
  828. LPWSTR pszClassName = NULL;
  829. //
  830. // get the from clause, i.e., the class names
  831. //
  832. if (pRpn->m_uFromTargetType & WMIQ_RPN_FROM_UNARY)
  833. {
  834. //
  835. // only one class
  836. //
  837. //
  838. // copy the class name and push it to our list
  839. //
  840. iLen = wcslen(pRpn->m_ppszFromList[0]);
  841. pszClassName = new WCHAR[iLen + 1];
  842. if (pszClassName != NULL)
  843. {
  844. //
  845. // won't overrun buffer, see size above
  846. //
  847. wcscpy(pszClassName, pRpn->m_ppszFromList[0]);
  848. m_vecClassList.push_back(pszClassName);
  849. }
  850. else
  851. {
  852. hr = E_OUTOFMEMORY;
  853. }
  854. }
  855. else if (pRpn->m_uFromTargetType & WMIQ_RPN_FROM_CLASS_LIST)
  856. {
  857. //
  858. // multiple classes. Won't happen for the time being. But we want to be ready
  859. // for WMI parser's enhancement.
  860. //
  861. for (ULONG uIndex = 0; uIndex < pRpn->m_uFromListSize; uIndex++)
  862. {
  863. iLen = wcslen(pRpn->m_ppszFromList[uIndex]);
  864. pszClassName = new WCHAR[iLen + 1];
  865. if (pszClassName != NULL)
  866. {
  867. //
  868. // won't overrun buffer, see size above
  869. //
  870. wcscpy(pszClassName, pRpn->m_ppszFromList[uIndex]);
  871. m_vecClassList.push_back(pszClassName);
  872. }
  873. else
  874. {
  875. hr = E_OUTOFMEMORY;
  876. break;
  877. }
  878. }
  879. }
  880. return hr;
  881. }
  882. /*
  883. Routine Description:
  884. Name:
  885. CSceQueryParser::ExtractQueryingProperties
  886. Functionality:
  887. Private helper to get the class name(s) from the query results.
  888. Virtual:
  889. No.
  890. Arguments:
  891. pRpn - The query result.
  892. strQueryPropName - the querying property's name
  893. Return Value:
  894. Success: S_OK
  895. Failure:
  896. (1) E_INVALIDARG (illegal null or index out of range)
  897. (2) E_OUTOFMEMORY.
  898. Notes:
  899. (1) Since this is regular COM server interface function, we use regular COM errors
  900. instead of WMI errors. However, we can't guarantee what WMI returns.
  901. (2) We only care about one querying property. Each subexpression will only have one querying property.
  902. Plus, if the subexpressions are AND'ed together, we will skip the rest subexpressions until we
  903. sees an OR again.
  904. (3) We can't support NOT very well. For example, how can we answer:
  905. select * from where NOT (SceStorePath = "c:\\test.inf")
  906. Fundamentally, we can't do that because we don't know the score of files not equal "c:\\test.inf".
  907. */
  908. //------------------------------------------------------------------------------------------------
  909. //------------------------------------------------------------------------------------------------
  910. HRESULT CSceQueryParser::ExtractQueryingProperties (
  911. IN SWbemRpnEncodedQuery * pRpn,
  912. IN LPCWSTR strQueryPropName
  913. )
  914. {
  915. if (pRpn == NULL)
  916. {
  917. return E_INVALIDARG;
  918. }
  919. HRESULT hr = S_OK;
  920. SWbemRpnQueryToken *pQueryToken = NULL;
  921. //
  922. // flags if we should ignore the next token
  923. //
  924. bool bSkip = false;
  925. for (ULONG uIndex = 0; uIndex < pRpn->m_uWhereClauseSize; uIndex++)
  926. {
  927. pQueryToken = pRpn->m_ppRpnWhereClause[uIndex];
  928. switch (pQueryToken->m_uTokenType)
  929. {
  930. case WMIQ_RPN_TOKEN_EXPRESSION:
  931. //
  932. // there is a subexpression, potentially a querying property here
  933. //
  934. if (!bSkip)
  935. {
  936. hr = GetQueryPropFromToken(pQueryToken, strQueryPropName);
  937. }
  938. //
  939. // if hr == S_FALSE, then it means it doesn't find any Store path
  940. // see it's use in case WMIQ_RPN_TOKEN_AND bellow
  941. //
  942. if (FAILED(hr))
  943. {
  944. return hr;
  945. }
  946. break;
  947. case WMIQ_RPN_TOKEN_OR:
  948. //
  949. // we see an OR, next tokens should NOT been skipped
  950. //
  951. bSkip = false;
  952. break;
  953. case WMIQ_RPN_TOKEN_AND:
  954. //
  955. // see comments about S_FALSE in case WMIQ_RPN_TOKEN_EXPRESSION above
  956. //
  957. bSkip = (hr == S_FALSE) ? false : true;
  958. //
  959. // fall through
  960. //
  961. case WMIQ_RPN_TOKEN_NOT:
  962. default:
  963. //
  964. // don't support parsing these tokens, so skip
  965. //
  966. bSkip = true;
  967. break;
  968. }
  969. }
  970. return S_OK;
  971. }
  972. /*
  973. Routine Description:
  974. Name:
  975. CSceQueryParser::GetQueryPropFromToken
  976. Functionality:
  977. Private helper analyze the token and get the querying property's value if found.
  978. Virtual:
  979. No.
  980. Arguments:
  981. pRpnQueryToken - The token to analyze.
  982. strQueryPropName - the querying property's name
  983. Return Value:
  984. Success: S_OK if a querying property's value is successfully retrieved.
  985. S_FALSE if no querying property name if found in the token.
  986. Failure:
  987. (1) E_INVALIDARG (illegal null or index out of range)
  988. (2) E_OUTOFMEMORY.
  989. (3) Other errors only defined by WMI, such as WBEM_E_INVALID_SYNTAX, WBEM_E_NOT_SUPPORTED.
  990. Notes:
  991. (1) Since this is regular COM server interface function, we use regular COM errors
  992. instead of WMI errors. However, we can't guarantee what WMI returns.
  993. (2) We only care about one querying property. Each subexpression will only have one querying property.
  994. Plus, if the subexpressions are AND'ed together, we will skip the rest subexpressions until we
  995. sees an OR again.
  996. (3) We can't support NOT very well. For example, how can we answer:
  997. select * from where NOT (SceStorePath = "c:\\test.inf")
  998. Fundamentally, we can't do that because we don't know the score of files not equal "c:\\test.inf".
  999. */
  1000. HRESULT
  1001. CSceQueryParser::GetQueryPropFromToken (
  1002. IN SWbemRpnQueryToken * pRpnQueryToken,
  1003. IN LPCWSTR strQueryPropName
  1004. )
  1005. {
  1006. HRESULT hr = S_OK;
  1007. //
  1008. // we only support <propertyName> = <value> and
  1009. // <value> should be string
  1010. //
  1011. if (pRpnQueryToken->m_uOperator != WMIQ_RPN_OP_EQ ||
  1012. pRpnQueryToken->m_uConstApparentType != VT_LPWSTR )
  1013. {
  1014. return WBEM_E_NOT_SUPPORTED;
  1015. }
  1016. //
  1017. // must have left identifier, we don't support it if it doesn't have one.
  1018. //
  1019. if (pRpnQueryToken->m_pLeftIdent == NULL)
  1020. {
  1021. hr = WBEM_E_NOT_SUPPORTED;
  1022. }
  1023. else
  1024. {
  1025. SWbemQueryQualifiedName *pLeft = pRpnQueryToken->m_pLeftIdent;
  1026. //
  1027. // no left, invalid
  1028. //
  1029. if (pLeft == NULL)
  1030. {
  1031. return WBEM_E_INVALID_SYNTAX;
  1032. }
  1033. if (pLeft->m_uNameListSize != 1)
  1034. {
  1035. return WBEM_E_NOT_SUPPORTED;
  1036. }
  1037. // if the right is StoreName, then this is what we need
  1038. if (_wcsicmp(strQueryPropName, pLeft->m_ppszNameList[0]) == 0)
  1039. {
  1040. int iLen = wcslen(pRpnQueryToken->m_Const.m_pszStrVal);
  1041. LPWSTR pName = new WCHAR[iLen + 1];
  1042. if (pName)
  1043. {
  1044. //
  1045. // won't overrun the buffer
  1046. //
  1047. wcscpy(pName, pRpnQueryToken->m_Const.m_pszStrVal);
  1048. m_vecQueryingPropValueList.push_back(pName);
  1049. }
  1050. else
  1051. {
  1052. return E_OUTOFMEMORY;
  1053. }
  1054. }
  1055. else
  1056. {
  1057. //
  1058. // no match for querying property name
  1059. //
  1060. hr = S_FALSE;
  1061. }
  1062. }
  1063. return hr;
  1064. }
  1065. /*
  1066. Routine Description:
  1067. Name:
  1068. CSceQueryParser::GetQueryPropFromToken
  1069. Functionality:
  1070. Get key proeprty value parsed from the query. Due to our query limitation, the property name
  1071. should really be the querying property name.
  1072. Virtual:
  1073. Yes.
  1074. Arguments:
  1075. pszKeyPropName - The key property name.
  1076. pvarValue - receives the value.
  1077. Return Value:
  1078. Success: S_OK if a key property's value is successfully retrieved.
  1079. WBEM_S_FALSE if the property can't be found.
  1080. Failure:
  1081. (1) E_INVALIDARG (illegal null or index out of range)
  1082. (2) E_OUTOFMEMORY.
  1083. (3) Other errors only defined by WMI, such as WBEM_E_INVALID_SYNTAX, WBEM_E_NOT_SUPPORTED.
  1084. Notes:
  1085. (1) Since this is regular COM server interface function, we use regular COM errors
  1086. instead of WMI errors. However, we can't guarantee what WMI returns.
  1087. */
  1088. STDMETHODIMP
  1089. CSceQueryParser::GetKeyPropertyValue (
  1090. IN LPCWSTR pszKeyPropName,
  1091. OUT VARIANT * pvarValue
  1092. )
  1093. {
  1094. if (pvarValue == NULL)
  1095. {
  1096. return E_INVALIDARG;
  1097. }
  1098. //
  1099. // ready to say that we can't find it
  1100. //
  1101. HRESULT hr = WBEM_S_FALSE;
  1102. ::VariantInit(pvarValue);
  1103. //
  1104. // If you are asking for the querying property's value, we certainly can give you one.
  1105. //
  1106. if ((LPCWSTR)m_bstrQueryingPropName != NULL && _wcsicmp(pszKeyPropName, m_bstrQueryingPropName) == 0)
  1107. {
  1108. CComBSTR bstrVal;
  1109. if (SUCCEEDED(GetQueryingPropertyValue(0, &bstrVal)))
  1110. {
  1111. //
  1112. // hand it over to the out parameter
  1113. //
  1114. pvarValue->vt = VT_BSTR;
  1115. pvarValue->bstrVal = bstrVal.Detach();
  1116. hr = S_OK;
  1117. }
  1118. else
  1119. {
  1120. hr = WBEM_S_FALSE;
  1121. }
  1122. }
  1123. return hr;
  1124. }