Team Fortress 2 Source Code as on 22/4/2020
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.

854 lines
20 KiB

  1. /*******************************************************************************
  2. * SPDDKHLP.h *
  3. *------------*
  4. * Description:
  5. * This is the header file for core helper functions implementation.
  6. *
  7. * Copyright (c) Microsoft Corporation. All rights reserved.
  8. *
  9. *******************************************************************************/
  10. #ifndef SPDDKHLP_h
  11. #define SPDDKHLP_h
  12. #ifndef SPHelper_h
  13. #include <sphelper.h>
  14. #endif
  15. #include <sapiddk.h>
  16. #ifndef SPError_h
  17. #include <SPError.h>
  18. #endif
  19. #ifndef SPDebug_h
  20. #include <SPDebug.h>
  21. #endif
  22. #ifndef _INC_LIMITS
  23. #include <limits.h>
  24. #endif
  25. #ifndef _INC_CRTDBG
  26. #include <crtdbg.h>
  27. #endif
  28. #ifndef _INC_MALLOC
  29. #include <malloc.h>
  30. #endif
  31. #ifndef _INC_MMSYSTEM
  32. #include <mmsystem.h>
  33. #endif
  34. #ifndef __comcat_h__
  35. #include <comcat.h>
  36. #endif
  37. //=== Constants ==============================================================
  38. #define sp_countof(x) ((sizeof(x) / sizeof(*(x))))
  39. #define SP_IS_BAD_WRITE_PTR(p) ( SPIsBadWritePtr( p, sizeof(*(p)) ))
  40. #define SP_IS_BAD_READ_PTR(p) ( SPIsBadReadPtr( p, sizeof(*(p)) ))
  41. #define SP_IS_BAD_CODE_PTR(p) ( ::IsBadCodePtr((FARPROC)(p) )
  42. #define SP_IS_BAD_INTERFACE_PTR(p) ( SPIsBadInterfacePtr( (p) ) )
  43. #define SP_IS_BAD_VARIANT_PTR(p) ( SPIsBadVARIANTPtr( (p) ) )
  44. #define SP_IS_BAD_STRING_PTR(p) ( SPIsBadStringPtr( (p) ) )
  45. #define SP_IS_BAD_OPTIONAL_WRITE_PTR(p) ((p) && SPIsBadWritePtr( p, sizeof(*(p)) ))
  46. #define SP_IS_BAD_OPTIONAL_READ_PTR(p) ((p) && SPIsBadReadPtr( p, sizeof(*(p)) ))
  47. #define SP_IS_BAD_OPTIONAL_INTERFACE_PTR(p) ((p) && SPIsBadInterfacePtr(p))
  48. #define SP_IS_BAD_OPTIONAL_STRING_PTR(p) ((p) && SPIsBadStringPtr(p))
  49. //=== Class, Enum, Struct, Template, and Union Declarations ==================
  50. //=== Inlines ================================================================
  51. /*** Pointer validation functions
  52. */
  53. // TODO: Add decent debug output for bad parameters
  54. inline BOOL SPIsBadStringPtr( const WCHAR * psz, ULONG cMaxChars = 0xFFFF )
  55. {
  56. BOOL IsBad = false;
  57. __try
  58. {
  59. do
  60. {
  61. if( *psz++ == 0 ) return IsBad;
  62. }
  63. while( --cMaxChars );
  64. }
  65. __except( GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION )
  66. {
  67. IsBad = true;
  68. }
  69. return IsBad;
  70. }
  71. inline BOOL SPIsBadReadPtr( const void* pMem, UINT Size )
  72. {
  73. #ifdef _DEBUG
  74. BOOL bIsBad = ::IsBadReadPtr( pMem, Size );
  75. SPDBG_ASSERT(!bIsBad);
  76. return bIsBad;
  77. #else
  78. return ::IsBadReadPtr( pMem, Size );
  79. #endif
  80. }
  81. inline BOOL SPIsBadWritePtr( void* pMem, UINT Size )
  82. {
  83. #ifdef _DEBUG
  84. BOOL bIsBad = ::IsBadWritePtr( pMem, Size );
  85. SPDBG_ASSERT(!bIsBad);
  86. return bIsBad;
  87. #else
  88. return ::IsBadWritePtr( pMem, Size );
  89. #endif
  90. }
  91. inline BOOL SPIsBadInterfacePtr( const IUnknown* pUnknown )
  92. {
  93. #ifdef _DEBUG
  94. BOOL bIsBad = ( ::IsBadReadPtr( pUnknown, sizeof( *pUnknown ) ) ||
  95. ::IsBadCodePtr( (FARPROC)((void**)pUnknown)[0] ))?
  96. (true):(false);
  97. SPDBG_ASSERT(!bIsBad);
  98. return bIsBad;
  99. #else
  100. return ( ::IsBadReadPtr( pUnknown, sizeof( *pUnknown ) ) ||
  101. ::IsBadCodePtr( (FARPROC)((void**)pUnknown)[0] ))?
  102. (true):(false);
  103. #endif
  104. }
  105. inline BOOL SPIsBadVARIANTPtr( const VARIANT* pVar )
  106. {
  107. #ifdef _DEBUG
  108. BOOL bIsBad = ::IsBadReadPtr( pVar, sizeof( *pVar ) );
  109. SPDBG_ASSERT(!bIsBad);
  110. return bIsBad;
  111. #else
  112. return ::IsBadReadPtr( pVar, sizeof( *pVar ) );
  113. #endif
  114. }
  115. #ifdef __ATLCOM_H__ //--- Only enable these if ATL is being used
  116. //
  117. // Helper functions can be used to implement GetObjectToken/SetObjectToken for objects that
  118. // support ISpObjectWithToken
  119. //
  120. inline HRESULT SpGenericSetObjectToken(ISpObjectToken * pCallersToken, CComPtr<ISpObjectToken> & cpObjToken)
  121. {
  122. HRESULT hr = S_OK;
  123. if (SP_IS_BAD_INTERFACE_PTR(pCallersToken))
  124. {
  125. hr = E_INVALIDARG;
  126. }
  127. else
  128. {
  129. if (cpObjToken)
  130. {
  131. hr = SPERR_ALREADY_INITIALIZED;
  132. }
  133. else
  134. {
  135. cpObjToken = pCallersToken;
  136. }
  137. }
  138. return hr;
  139. }
  140. inline HRESULT SpGenericGetObjectToken(ISpObjectToken ** ppCallersToken, CComPtr<ISpObjectToken> & cpObjToken)
  141. {
  142. HRESULT hr = S_OK;
  143. if (SP_IS_BAD_WRITE_PTR(ppCallersToken))
  144. {
  145. hr = E_POINTER;
  146. }
  147. else
  148. {
  149. *ppCallersToken = cpObjToken;
  150. if (*ppCallersToken)
  151. {
  152. (*ppCallersToken)->AddRef();
  153. }
  154. else
  155. {
  156. hr = S_FALSE;
  157. }
  158. }
  159. return hr;
  160. }
  161. #endif // __ATLCOM_H__
  162. //
  163. // Helper class for SPSTATEINFO sturcture automatically initializes and cleans up
  164. // the structure + provides a few helper functions.
  165. //
  166. class CSpStateInfo : public SPSTATEINFO
  167. {
  168. public:
  169. CSpStateInfo()
  170. {
  171. cAllocatedEntries = NULL;
  172. pTransitions = NULL;
  173. }
  174. ~CSpStateInfo()
  175. {
  176. ::CoTaskMemFree(pTransitions);
  177. }
  178. SPTRANSITIONENTRY * FirstEpsilon()
  179. {
  180. return pTransitions;
  181. }
  182. SPTRANSITIONENTRY * FirstRule()
  183. {
  184. return pTransitions + cEpsilons;
  185. }
  186. SPTRANSITIONENTRY * FirstWord()
  187. {
  188. return pTransitions + cEpsilons + cRules;
  189. }
  190. SPTRANSITIONENTRY * FirstSpecialTransition()
  191. {
  192. return pTransitions + cEpsilons + cRules + cWords;
  193. }
  194. };
  195. //
  196. // This basic queue implementation can be used to maintin linked lists of classes. The class T
  197. // must contain the member m_pNext which is used by this template to point to the next element.
  198. // If the bPurgeWhenDeleted is TRUE then all of the elements in the queue will be deleted
  199. // when the queue is deleted, otherwise they will not.
  200. // If bMaintainCount is TRUE then a running count will be maintained, and GetCount() will be
  201. // efficent. If it is FALSE then a running count will not be maintained, and GetCount() will
  202. // be an order N operation. If you do not require a count, then
  203. //
  204. template <class T, BOOL bPurgeWhenDeleted> class CSpBasicList;
  205. template <class T, BOOL bPurgeWhenDeleted = TRUE, BOOL bMaintainCount = FALSE>
  206. class CSpBasicQueue
  207. {
  208. public:
  209. T * m_pHead;
  210. T * m_pTail;
  211. ULONG m_cElements; // Warning! Use GetCount() -- Not maintained if bMaintainCount is FALSE.
  212. CSpBasicQueue()
  213. {
  214. m_pHead = NULL;
  215. if (bMaintainCount)
  216. {
  217. m_cElements = 0;
  218. }
  219. }
  220. ~CSpBasicQueue()
  221. {
  222. if (bPurgeWhenDeleted)
  223. {
  224. Purge();
  225. }
  226. }
  227. HRESULT CreateNode(T ** ppNode)
  228. {
  229. *ppNode = new T;
  230. if (*ppNode)
  231. {
  232. return S_OK;
  233. }
  234. else
  235. {
  236. return E_OUTOFMEMORY;
  237. }
  238. }
  239. T * GetNext(const T * pNode)
  240. {
  241. return pNode->m_pNext;
  242. }
  243. T * Item(ULONG i)
  244. {
  245. T * pNode = m_pHead;
  246. while (pNode && i)
  247. {
  248. i--;
  249. pNode = pNode->m_pNext;
  250. }
  251. return pNode;
  252. }
  253. void InsertAfter(T * pPrev, T * pNewNode)
  254. {
  255. if (pPrev)
  256. {
  257. pNewNode->m_pNext = pPrev->m_pNext;
  258. pPrev->m_pNext = pNewNode;
  259. if (pNewNode->m_pNext == NULL)
  260. {
  261. m_pTail = pNewNode;
  262. }
  263. if (bMaintainCount) ++m_cElements;
  264. }
  265. else
  266. {
  267. InsertHead(pNewNode);
  268. }
  269. }
  270. void InsertTail(T * pNode)
  271. {
  272. pNode->m_pNext = NULL;
  273. if (m_pHead)
  274. {
  275. m_pTail->m_pNext = pNode;
  276. }
  277. else
  278. {
  279. m_pHead = pNode;
  280. }
  281. m_pTail = pNode;
  282. if (bMaintainCount) ++m_cElements;
  283. }
  284. void InsertHead(T * pNode)
  285. {
  286. pNode->m_pNext = m_pHead;
  287. if (m_pHead == NULL)
  288. {
  289. m_pTail = pNode;
  290. }
  291. m_pHead = pNode;
  292. if (bMaintainCount) ++m_cElements;
  293. }
  294. T * RemoveHead()
  295. {
  296. T * pNode = m_pHead;
  297. if (pNode)
  298. {
  299. m_pHead = pNode->m_pNext;
  300. if (bMaintainCount) --m_cElements;
  301. }
  302. return pNode;
  303. }
  304. T * RemoveTail()
  305. {
  306. T * pNode = m_pHead;
  307. if (pNode)
  308. {
  309. if (pNode == m_pTail)
  310. {
  311. m_pHead = NULL;
  312. }
  313. else
  314. {
  315. T * pPrev;
  316. do
  317. {
  318. pPrev = pNode;
  319. pNode = pNode->m_pNext;
  320. } while ( pNode != m_pTail );
  321. pPrev->m_pNext = NULL;
  322. m_pTail = pPrev;
  323. }
  324. if (bMaintainCount) --m_cElements;
  325. }
  326. return pNode;
  327. }
  328. void Purge()
  329. {
  330. while (m_pHead)
  331. {
  332. T * pDie = m_pHead;
  333. m_pHead = pDie->m_pNext;
  334. delete pDie;
  335. }
  336. if (bMaintainCount) m_cElements = 0;
  337. }
  338. void ExplicitPurge()
  339. {
  340. T * pDie;
  341. BYTE * pb;
  342. while (m_pHead)
  343. {
  344. pDie = m_pHead;
  345. m_pHead = pDie->m_pNext;
  346. pDie->~T();
  347. pb = reinterpret_cast<BYTE *>(pDie);
  348. delete [] pb;
  349. }
  350. if (bMaintainCount) m_cElements = 0;
  351. }
  352. T * GetTail() const
  353. {
  354. if (m_pHead)
  355. {
  356. return m_pTail;
  357. }
  358. return NULL;
  359. }
  360. T * GetHead() const
  361. {
  362. return m_pHead;
  363. }
  364. BOOL IsEmpty() const
  365. {
  366. return m_pHead == NULL;
  367. }
  368. BOOL Remove(T * pNode)
  369. {
  370. if (m_pHead == pNode)
  371. {
  372. m_pHead = pNode->m_pNext;
  373. if (bMaintainCount) --m_cElements;
  374. return TRUE;
  375. }
  376. else
  377. {
  378. T * pCur = m_pHead;
  379. while (pCur)
  380. {
  381. T * pNext = pCur->m_pNext;
  382. if (pNext == pNode)
  383. {
  384. if ((pCur->m_pNext = pNode->m_pNext) == NULL)
  385. {
  386. m_pTail = pCur;
  387. }
  388. if (bMaintainCount) --m_cElements;
  389. return TRUE;
  390. }
  391. pCur = pNext;
  392. }
  393. }
  394. return FALSE;
  395. }
  396. void MoveAllToHeadOf(CSpBasicQueue & DestQueue)
  397. {
  398. if (m_pHead)
  399. {
  400. m_pTail->m_pNext = DestQueue.m_pHead;
  401. if (DestQueue.m_pHead == NULL)
  402. {
  403. DestQueue.m_pTail = m_pTail;
  404. }
  405. DestQueue.m_pHead = m_pHead;
  406. m_pHead = NULL;
  407. if (bMaintainCount)
  408. {
  409. DestQueue.m_cElements += m_cElements;
  410. m_cElements = 0;
  411. }
  412. }
  413. }
  414. void MoveAllToList(CSpBasicList<T, bPurgeWhenDeleted> & List)
  415. {
  416. if (m_pHead)
  417. {
  418. m_pTail->m_pNext = List.m_pFirst;
  419. List.m_pFirst = m_pHead;
  420. m_pHead = NULL;
  421. }
  422. if (bMaintainCount)
  423. {
  424. m_cElements = 0;
  425. }
  426. }
  427. BOOL MoveToList(T * pNode, CSpBasicList<T, bPurgeWhenDeleted> & List)
  428. {
  429. BOOL bFound = Remove(pNode);
  430. if (bFound)
  431. {
  432. List.AddNode(pNode);
  433. }
  434. return bFound;
  435. }
  436. ULONG GetCount() const
  437. {
  438. if (bMaintainCount)
  439. {
  440. return m_cElements;
  441. }
  442. else
  443. {
  444. ULONG c = 0;
  445. for (T * pNode = m_pHead;
  446. pNode;
  447. pNode = pNode->m_pNext, c++) {}
  448. return c;
  449. }
  450. }
  451. //
  452. // The following functions require the class T to implement a static function:
  453. //
  454. // LONG Compare(const T * pElem1, const T * pElem2)
  455. //
  456. // which returns < 0 if pElem1 is less than pElem2, 0 if they are equal, and > 0 if
  457. // pElem1 is greater than pElem2.
  458. //
  459. void InsertSorted(T * pNode)
  460. {
  461. if (m_pHead)
  462. {
  463. if (T::Compare(pNode, m_pTail) >= 0)
  464. {
  465. pNode->m_pNext = NULL;
  466. m_pTail->m_pNext = pNode;
  467. m_pTail = pNode;
  468. }
  469. else
  470. {
  471. //
  472. // We don't have to worry about walking off of the end of the list here since
  473. // we have already checked the tail.
  474. //
  475. T ** ppNext = &m_pHead;
  476. while (T::Compare(pNode, *ppNext) >= 0)
  477. {
  478. ppNext = &((*ppNext)->m_pNext);
  479. }
  480. pNode->m_pNext = *ppNext;
  481. *ppNext = pNode;
  482. }
  483. }
  484. else
  485. {
  486. pNode->m_pNext = NULL;
  487. m_pHead = m_pTail = pNode;
  488. }
  489. if (bMaintainCount) ++m_cElements;
  490. }
  491. HRESULT InsertSortedUnique(T * pNode)
  492. {
  493. HRESULT hr = S_OK;
  494. if (m_pHead)
  495. {
  496. if (T::Compare(pNode, m_pTail) > 0)
  497. {
  498. pNode->m_pNext = NULL;
  499. m_pTail->m_pNext = pNode;
  500. m_pTail = pNode;
  501. }
  502. else
  503. {
  504. //
  505. // We don't have to worry about walking off of the end of the list here since
  506. // we have already checked the tail.
  507. //
  508. T ** ppNext = &m_pHead;
  509. while (T::Compare(pNode, *ppNext) > 0)
  510. {
  511. ppNext = &((*ppNext)->m_pNext);
  512. }
  513. if (T::Compare(pNode, *ppNext) != 0)
  514. {
  515. pNode->m_pNext = *ppNext;
  516. *ppNext = pNode;
  517. }
  518. else
  519. {
  520. delete pNode;
  521. hr = S_FALSE;
  522. }
  523. }
  524. }
  525. else
  526. {
  527. pNode->m_pNext = NULL;
  528. m_pHead = m_pTail = pNode;
  529. }
  530. if (bMaintainCount) ++m_cElements;
  531. return hr;
  532. }
  533. //
  534. // These functions must support the "==" operator for the TFIND type.
  535. //
  536. template <class TFIND>
  537. T * Find(TFIND & FindVal) const
  538. {
  539. for (T * pNode = m_pHead; pNode && (!(*pNode == FindVal)); pNode = pNode->m_pNext)
  540. {}
  541. return pNode;
  542. }
  543. template <class TFIND>
  544. T * FindNext(const T * pCurNode, TFIND & FindVal) const
  545. {
  546. for (T * pNode = pCurNode->m_pNext; pNode && (!(*pNode == FindVal)); pNode = pNode->m_pNext)
  547. {}
  548. return pNode;
  549. }
  550. //
  551. // Searches for and removes a single list element
  552. //
  553. template <class TFIND>
  554. T * FindAndRemove(TFIND & FindVal)
  555. {
  556. T * pNode = m_pHead;
  557. if (pNode)
  558. {
  559. if (*pNode == FindVal)
  560. {
  561. m_pHead = pNode->m_pNext;
  562. if (bMaintainCount) --m_cElements;
  563. }
  564. else
  565. {
  566. T * pPrev = pNode;
  567. for (pNode = pNode->m_pNext;
  568. pNode;
  569. pPrev = pNode, pNode = pNode->m_pNext)
  570. {
  571. if (*pNode == FindVal)
  572. {
  573. pPrev->m_pNext = pNode->m_pNext;
  574. if (pNode->m_pNext == NULL)
  575. {
  576. m_pTail = pPrev;
  577. }
  578. if (bMaintainCount) --m_cElements;
  579. break;
  580. }
  581. }
  582. }
  583. }
  584. return pNode;
  585. }
  586. //
  587. // Searches for and deletes all list elements that match
  588. //
  589. template <class TFIND>
  590. void FindAndDeleteAll(TFIND & FindVal)
  591. {
  592. T * pNode = m_pHead;
  593. while (pNode && *pNode == FindVal)
  594. {
  595. m_pHead = pNode->m_pNext;
  596. delete pNode;
  597. if (bMaintainCount) --m_cElements;
  598. pNode = m_pHead;
  599. }
  600. T * pPrev = pNode;
  601. while (pNode)
  602. {
  603. T * pNext = pNode->m_pNext;
  604. if (*pNode == FindVal)
  605. {
  606. pPrev->m_pNext = pNext;
  607. delete pNode;
  608. if (bMaintainCount) --m_cElements;
  609. }
  610. else
  611. {
  612. pPrev = pNode;
  613. }
  614. pNode = pNext;
  615. }
  616. m_pTail = pPrev; // Just always set it in case we removed the tail.
  617. }
  618. };
  619. template <class T, BOOL bPurgeWhenDeleted = TRUE>
  620. class CSpBasicList
  621. {
  622. public:
  623. T * m_pFirst;
  624. CSpBasicList() : m_pFirst(NULL) {}
  625. ~CSpBasicList()
  626. {
  627. if (bPurgeWhenDeleted)
  628. {
  629. Purge();
  630. }
  631. }
  632. void Purge()
  633. {
  634. while (m_pFirst)
  635. {
  636. T * pNext = m_pFirst->m_pNext;
  637. delete m_pFirst;
  638. m_pFirst = pNext;
  639. }
  640. }
  641. void ExplicitPurge()
  642. {
  643. T * pDie;
  644. BYTE * pb;
  645. while (m_pFirst)
  646. {
  647. pDie = m_pFirst;
  648. m_pFirst = pDie->m_pNext;
  649. pDie->~T();
  650. pb = reinterpret_cast<BYTE *>(pDie);
  651. delete [] pb;
  652. }
  653. }
  654. HRESULT RemoveFirstOrAllocateNew(T ** ppNode)
  655. {
  656. if (m_pFirst)
  657. {
  658. *ppNode = m_pFirst;
  659. m_pFirst = m_pFirst->m_pNext;
  660. }
  661. else
  662. {
  663. *ppNode = new T;
  664. if (*ppNode == NULL)
  665. {
  666. return E_OUTOFMEMORY;
  667. }
  668. }
  669. return S_OK;
  670. }
  671. void AddNode(T * pNode)
  672. {
  673. pNode->m_pNext = m_pFirst;
  674. m_pFirst = pNode;
  675. }
  676. T * GetFirst()
  677. {
  678. return m_pFirst;
  679. }
  680. T * RemoveFirst()
  681. {
  682. T * pNode = m_pFirst;
  683. if (pNode)
  684. {
  685. m_pFirst = pNode->m_pNext;
  686. }
  687. return pNode;
  688. }
  689. };
  690. #define STACK_ALLOC(TYPE, COUNT) (TYPE *)_alloca(sizeof(TYPE) * (COUNT))
  691. #define STACK_ALLOC_AND_ZERO(TYPE, COUNT) (TYPE *)memset(_alloca(sizeof(TYPE) * (COUNT)), 0, (sizeof(TYPE) * (COUNT)))
  692. #define STACK_ALLOC_AND_COPY(TYPE, COUNT, SOURCE) (TYPE *)memcpy(_alloca(sizeof(TYPE) * (COUNT)), (SOURCE), (sizeof(TYPE) * (COUNT)))
  693. inline HRESULT SpGetSubTokenFromToken(
  694. ISpObjectToken * pToken,
  695. const WCHAR * pszSubKeyName,
  696. ISpObjectToken ** ppToken,
  697. BOOL fCreateIfNotExist = FALSE)
  698. {
  699. SPDBG_FUNC("SpGetTokenFromDataKey");
  700. HRESULT hr = S_OK;
  701. if (SP_IS_BAD_INTERFACE_PTR(pToken) ||
  702. SP_IS_BAD_STRING_PTR(pszSubKeyName) ||
  703. SP_IS_BAD_WRITE_PTR(ppToken))
  704. {
  705. hr = E_POINTER;
  706. }
  707. // First, either create or open the datakey for the new token
  708. CComPtr<ISpDataKey> cpDataKeyForNewToken;
  709. if (SUCCEEDED(hr))
  710. {
  711. if (fCreateIfNotExist)
  712. {
  713. hr = pToken->CreateKey(pszSubKeyName, &cpDataKeyForNewToken);
  714. }
  715. else
  716. {
  717. hr = pToken->OpenKey(pszSubKeyName, &cpDataKeyForNewToken);
  718. }
  719. }
  720. // The sub token's category will be the token id of it's parent token
  721. CSpDynamicString dstrCategoryId;
  722. if (SUCCEEDED(hr))
  723. {
  724. hr = pToken->GetId(&dstrCategoryId);
  725. }
  726. // The sub token's token id will be it's category id + "\\" the key name
  727. CSpDynamicString dstrTokenId;
  728. if (SUCCEEDED(hr))
  729. {
  730. dstrTokenId = dstrCategoryId;
  731. dstrTokenId.Append2(L"\\", pszSubKeyName);
  732. }
  733. // Now create the token and initalize it
  734. CComPtr<ISpObjectTokenInit> cpTokenInit;
  735. if (SUCCEEDED(hr))
  736. {
  737. hr = cpTokenInit.CoCreateInstance(CLSID_SpObjectToken);
  738. }
  739. if (SUCCEEDED(hr))
  740. {
  741. hr = cpTokenInit->InitFromDataKey(dstrCategoryId, dstrTokenId, cpDataKeyForNewToken);
  742. }
  743. if (SUCCEEDED(hr))
  744. {
  745. *ppToken = cpTokenInit.Detach();
  746. }
  747. SPDBG_REPORT_ON_FAIL(hr);
  748. return hr;
  749. }
  750. template<class T>
  751. HRESULT SpCreateObjectFromSubToken(ISpObjectToken * pToken, const WCHAR * pszSubKeyName, T ** ppObject,
  752. IUnknown * pUnkOuter = NULL, DWORD dwClsCtxt = CLSCTX_ALL)
  753. {
  754. SPDBG_FUNC("SpCreateObjectFromSubToken");
  755. HRESULT hr;
  756. CComPtr<ISpObjectToken> cpSubToken;
  757. hr = SpGetSubTokenFromToken(pToken, pszSubKeyName, &cpSubToken);
  758. if (SUCCEEDED(hr))
  759. {
  760. hr = SpCreateObjectFromToken(cpSubToken, ppObject, pUnkOuter, dwClsCtxt);
  761. }
  762. SPDBG_REPORT_ON_FAIL(hr);
  763. return hr;
  764. }
  765. #endif /* This must be the last line in the file */