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.

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